home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / modex105 / modex.asm < prev    next >
Encoding:
Assembly Source File  |  1993-08-31  |  114.5 KB  |  3,300 lines

  1. ;========================================================
  2. ; MODEX.ASM - A Complete Mode X Library
  3. ;
  4. ; Version 1.05 Release, 31 Aug 1993, By Matt Pritchard
  5. ; With considerable input from Michael Abrash
  6. ;
  7. ; The following information is donated to the public domain in
  8. ; the hopes that save other programmers much frustration.
  9. ;
  10. ; If you do use this code in a product, it would be nice if
  11. ; you include a line like "Mode X routines by Matt Pritchard"
  12. ; in the credits.
  13. ;
  14. ; =========================================================
  15. ;
  16. ; All of this code is designed to be assembled with MASM 5.10a
  17. ; but TASM 3.0 could be used as well.
  18. ;
  19. ; The routines contained are designed for use in a MEDIUM model
  20. ; program.  All Routines are FAR, and is assumed that a DGROUP
  21. ; data segment exists and that DS will point to it on entry.
  22. ;
  23. ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers
  24. ; will not be preserved, while the DS, BP, SI and DI registers
  25. ; will be preserved.
  26. ;
  27. ; Unless specifically noted, All Parameters are assumed to be
  28. ; "PASSED BY VALUE".  That is, the actual value is placed on
  29. ; the stack.  When a reference is passed it is assumed to be
  30. ; a near pointer to a variable in the DGROUP segment.
  31. ;
  32. ; Routines that return a single 16-Bit integer value will
  33. ; return that value in the AX register.
  34. ;
  35. ; This code will *NOT* run on an 8086/8088 because 80286+
  36. ; specific instructions are used.   If you have an 8088/86
  37. ; and VGA, you can buy an 80386-40 motherboard for about
  38. ; $100 and move into the 90's.
  39. ;
  40. ; This code is reasonably optimized: Most drawing loops have
  41. ; been unrolled once and memory references are minimized by
  42. ; keeping stuff in registers when possible.
  43. ;
  44. ; Error Trapping varies by Routine.  No Clipping is performed
  45. ; so the caller should verify that all coordinates are valid.
  46. ;
  47. ; Several Macros are used to simplify common 2 or 3 instruction
  48. ; sequences.  Several Single letter Text Constants also
  49. ; simplify common assembler expressions like "WORD PTR".
  50. ;
  51. ; ------------------ Mode X Variations ------------------
  52. ;
  53. ;  Mode #  Screen Size    Max Pages   Aspect Ratio (X:Y)
  54. ;
  55. ;    0      320 x 200      4 Pages         1.2:1
  56. ;    1      320 x 400      2 Pages         2.4:1
  57. ;    2      360 x 200      3 Pages        1.35:1
  58. ;    3      360 x 400      1 Page          2.7:1
  59. ;    4      320 x 240      3 Pages           1:1
  60. ;    5      320 x 480      1 Page            2:1
  61. ;    6      360 x 240      3 Pages       1.125:1
  62. ;    7      360 x 480      1 Page         2.25:1
  63. ;
  64. ; -------------------- The Legal Stuff ------------------
  65. ;
  66. ; No warranty, either written or implied, is made as to
  67. ; the accuracy and usability of this code product.  Use
  68. ; at your own risk.  Batteries not included.  Pepperoni
  69. ; and extra cheese available for an additional charge.
  70. ;
  71. ; ----------------------- The Author --------------------
  72. ;
  73. ; Matt Pritchard is a paid programmer who'd rather be
  74. ; writing games.  He can be reached at: P.O. Box 140264,
  75. ; Irving, TX  75014  USA.  Michael Abrash is a living
  76. ; god, who now works for Bill Gates (Microsoft).
  77. ;
  78. ; -------------------- Revision History -----------------
  79. ; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI
  80. ;          SET_MODEX now saves SI
  81. ; 5-3-93:  v1.04 - added LOAD_DAC_REGISTERS and
  82. ;          READ_DAC_REGISTERS.  Expanded CLR Macro
  83. ;          to handle multiple registers
  84. ; 8-31-93: v1.05 - Recompiled CSEDIT and FONTEDIT to use
  85. ;          the default Microsoft Libraries instead of
  86. ;          Crescent's P.D.Q. which caused those program
  87. ;          to lock up on many computers.
  88. ;
  89.  
  90.     PAGE    255, 132
  91.  
  92.     .MODEL Medium
  93.     .286
  94.  
  95.     ; ===== MACROS =====
  96.  
  97.     ; Macro to OUT a 16 bit value to an I/O port
  98.  
  99. OUT_16 MACRO Register, Value
  100.     IFDIFI <Register>, <DX>         ; If DX not setup
  101.         MOV     DX, Register        ; then Select Register
  102.     ENDIF
  103.     IFDIFI <Value>, <AX>            ; If AX not setup
  104.         MOV     AX, Value           ; then Get Data Value
  105.     ENDIF
  106.         OUT     DX, AX              ; Set I/O Register(s)
  107. ENDM
  108.  
  109.     ; Macro to OUT a 8 bit value to an I/O Port
  110.  
  111. OUT_8 MACRO Register, Value
  112.     IFDIFI <Register>, <DX>         ; If DX not setup
  113.         MOV     DX, Register        ; then Select Register
  114.     ENDIF
  115.     IFDIFI <Value>, <AL>            ; If AL not Setup
  116.         MOV     AL, Value           ; then Get Data Value
  117.     ENDIF
  118.         OUT     DX, AL              ; Set I/O Register
  119. ENDM
  120.  
  121.     ; macros to PUSH and POP multiple registers
  122.  
  123. PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8
  124.     IFNB <R1>
  125.         PUSH    R1              ; Save R1
  126.         PUSHx   R2, R3, R4, R5, R6, R7, R8
  127.     ENDIF
  128. ENDM
  129.  
  130. POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8
  131.     IFNB <R1>
  132.         POP     R1              ; Restore R1
  133.         POPx    R2, R3, R4, R5, R6, R7, R8
  134.     ENDIF
  135. ENDM
  136.  
  137.     ; Macro to Clear Registers to 0
  138.  
  139. CLR MACRO Register, R2, R3, R4, R5, R6
  140.     IFNB <Register>
  141.         XOR     Register, Register      ; Set Register = 0
  142.         CLR R2, R3, R4, R5, R6
  143.     ENDIF
  144. ENDM
  145.  
  146.     ; Macros to Decrement Counter & Jump on Condition
  147.  
  148. LOOPx MACRO Register, Destination
  149.     DEC     Register                ; Counter--
  150.     JNZ     Destination             ; Jump if not 0
  151. ENDM
  152.  
  153. LOOPjz MACRO Register, Destination
  154.     DEC     Register                ; Counter--
  155.     JZ      Destination             ; Jump if 0
  156. ENDM
  157.  
  158.  
  159.     ; ===== General Constants =====
  160.  
  161.     False   EQU 0
  162.     True    EQU -1
  163.     nil     EQU 0
  164.  
  165.     b       EQU BYTE PTR
  166.     w       EQU WORD PTR
  167.     d       EQU DWORD PTR
  168.     o       EQU OFFSET
  169.     f       EQU FAR PTR
  170.     s       EQU SHORT
  171.     ?x4     EQU <?,?,?,?>
  172.     ?x3     EQU <?,?,?>
  173.  
  174.     ; ===== VGA Register Values =====
  175.  
  176.     VGA_Segment     EQU 0A000h  ; Vga Memory Segment
  177.  
  178.     ATTRIB_Ctrl     EQU 03C0h   ; VGA Attribute Controller
  179.     GC_Index        EQU 03CEh   ; VGA Graphics Controller
  180.     SC_Index        EQU 03C4h   ; VGA Sequencer Controller
  181.     SC_Data         EQU 03C5h   ; VGA Sequencer Data Port
  182.     CRTC_Index      EQU 03D4h   ; VGA CRT Controller
  183.     CRTC_Data       EQU 03D5h   ; VGA CRT Controller Data
  184.     MISC_OUTPUT     EQU 03C2h   ; VGA Misc Register
  185.     INPUT_1         EQU 03DAh   ; Input Status #1 Register
  186.  
  187.     DAC_WRITE_ADDR  EQU 03C8h   ; VGA DAC Write Addr Register
  188.     DAC_READ_ADDR   EQU 03C7h   ; VGA DAC Read Addr Register
  189.     PEL_DATA_REG    EQU 03C9h   ; VGA DAC/PEL data Register R/W
  190.  
  191.     PIXEL_PAN_REG   EQU 033h    ; Attrib Index: Pixel Pan Reg
  192.     MAP_MASK        EQU 002h    ; Sequ Index: Write Map Mask reg
  193.     READ_MAP        EQU 004h    ; GC Index: Read Map Register
  194.     START_DISP_HI   EQU 00Ch    ; CRTC Index: Display Start Hi
  195.     START_DISP_LO   EQU 00Dh    ; CRTC Index: Display Start Lo
  196.  
  197.     MAP_MASK_PLANE1 EQU 00102h  ; Map Register + Plane 1
  198.     MAP_MASK_PLANE2 EQU 01102h  ; Map Register + Plane 1
  199.     ALL_PLANES_ON   EQU 00F02h  ; Map Register + All Bit Planes
  200.  
  201.     CHAIN4_OFF      EQU 00604h  ; Chain 4 mode Off
  202.     ASYNC_RESET     EQU 00100h  ; (A)synchronous Reset
  203.     SEQU_RESTART    EQU 00300h  ; Sequencer Restart
  204.  
  205.     LATCHES_ON      EQU 00008h  ; Bit Mask + Data from Latches
  206.     LATCHES_OFF     EQU 0FF08h  ; Bit Mask + Data from CPU
  207.  
  208.     VERT_RETRACE    EQU 08h     ; INPUT_1: Vertical Retrace Bit
  209.     PLANE_BITS      EQU 03h     ; Bits 0-1 of Xpos = Plane #
  210.     ALL_PLANES      EQU 0Fh     ; All Bit Planes Selected
  211.     CHAR_BITS       EQU 0Fh     ; Bits 0-3 of Character Data
  212.  
  213.     GET_CHAR_PTR    EQU 01130h  ; VGA BIOS Func: Get Char Set
  214.     ROM_8x8_Lo      EQU 03h     ; ROM 8x8 Char Set Lo Pointer
  215.     ROM_8x8_Hi      EQU 04h     ; ROM 8x8 Char Set Hi Pointer
  216.  
  217.     ; Constants Specific for these routines
  218.  
  219.     NUM_MODES       EQU 8       ; # of Mode X Variations
  220.  
  221.     ; Specific Mode Data Table format...
  222.  
  223. Mode_Data_Table STRUC
  224.     M_MiscR         DB  ?       ; Value of MISC_OUTPUT register
  225.     M_Pages         DB  ?       ; Maximum Possible # of pages
  226.     M_XSize         DW  ?       ; X Size Displayed on screen
  227.     M_YSize         DW  ?       ; Y Size Displayed on screen
  228.     M_XMax          DW  ?       ; Maximum Possible X Size
  229.     M_YMax          DW  ?       ; Maximum Possible Y Size
  230.     M_CRTC          DW  ?       ; Table of CRTC register values
  231. Mode_Data_Table ENDS
  232.  
  233.     ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====
  234.  
  235.     .DATA?
  236.  
  237. SCREEN_WIDTH    DW  0       ; Width of a line in Bytes
  238. SCREEN_HEIGHT   DW  0       ; Vertical Height in Pixels
  239.  
  240. LAST_PAGE       DW  0       ; # of Display Pages
  241. PAGE_ADDR       DW  4 DUP (0)   ; Offsets to start of each page
  242.  
  243. PAGE_SIZE       DW  0       ; Size of Page in Addr Bytes
  244.  
  245. DISPLAY_PAGE    DW  0       ; Page # currently displayed
  246. ACTIVE_PAGE     DW  0       ; Page # currently active
  247.  
  248. CURRENT_PAGE    DW  0       ; Offset of current Page
  249. CURRENT_SEGMENT DW  0       ; Segment of VGA memory
  250.  
  251. CURRENT_XOFFSET DW  0       ; Current Display X Offset
  252. CURRENT_YOFFSET DW  0       ; Current Display Y Offset
  253.  
  254. CURRENT_MOFFSET DW  0       ; Current Start Offset
  255.  
  256. MAX_XOFFSET     DW  0       ; Current Display X Offset
  257. MAX_YOFFSET     DW  0       ; Current Display Y Offset
  258.  
  259. CHARSET_LOW     DW  0, 0    ; Far Ptr to Char Set: 0-127
  260. CHARSET_HI      DW  0, 0    ; Far Ptr to Char Set: 128-255
  261.  
  262.     .CODE
  263.  
  264.     ; ===== DATA TABLES =====
  265.  
  266.     ; Data Tables, Put in Code Segment for Easy Access
  267.     ; (Like when all the other Segment Registers are in
  268.     ; use!!) and reduced DGROUP requirements...
  269.  
  270.     ; Bit Mask Tables for Left/Right/Character Masks
  271.  
  272. Left_Clip_Mask      DB  0FH, 0EH, 0CH, 08H
  273.  
  274. Right_Clip_Mask     DB  01H, 03H, 07H, 0FH
  275.  
  276.     ; Bit Patterns for converting character fonts
  277.  
  278. Char_Plane_Data     DB  00H,08H,04H,0CH,02H,0AH,06H,0EH
  279.                     DB  01H,09H,05H,0DH,03H,0BH,07H,0FH
  280.  
  281.         ; CRTC Register Values for Various Configurations
  282.  
  283. MODE_Single_Line:       ; CRTC Setup Data for 400/480 Line modes
  284.         DW  04009H      ; Cell Height (1 Scan Line)
  285.         DW  00014H      ; Dword Mode off
  286.         DW  0E317H      ; turn on Byte Mode
  287.         DW  nil         ; End of CRTC Data for 400/480 Line Mode
  288.  
  289. MODE_Double_Line:       ; CRTC Setup Data for 200/240 Line modes
  290.         DW  04109H      ; Cell Height (2 Scan Lines)
  291.         DW  00014H      ; Dword Mode off
  292.         DW  0E317H      ; turn on Byte Mode
  293.         DW  nil         ; End of CRTC Data for 200/240 Line Mode
  294.  
  295. MODE_320_Wide:          ; CRTC Setup Data for 320 Horz Pixels
  296.         DW  05F00H      ; Horz total
  297.         DW  04F01H      ; Horz Displayed
  298.         DW  05002H      ; Start Horz Blanking
  299.         DW  08203H      ; End Horz Blanking
  300.         DW  05404H      ; Start H Sync
  301.         DW  08005H      ; End H Sync
  302.         DW  nil         ; End of CRTC Data for 320 Horz pixels
  303.  
  304. MODE_360_Wide:          ; CRTC Setup Data for 360 Horz Pixels
  305.         DW  06B00H      ; Horz total
  306.         DW  05901H      ; Horz Displayed
  307.         DW  05A02H      ; Start Horz Blanking
  308.         DW  08E03H      ; End Horz Blanking
  309.         DW  05E04H      ; Start H Sync
  310.         DW  08A05H      ; End H Sync
  311.         DW  nil         ; End of CRTC Data for 360 Horz pixels
  312.  
  313. MODE_200_Tall:
  314. MODE_400_Tall:          ; CRTC Setup Data for 200/400 Line modes
  315.         DW  0BF06H      ; Vertical Total
  316.         DW  01F07H      ; Overflow
  317.         DW  09C10H      ; V Sync Start
  318.         DW  08E11H      ; V Sync End/Prot Cr0 Cr7
  319.         DW  08F12H      ; Vertical Displayed
  320.         DW  09615H      ; V Blank Start
  321.         DW  0B916H      ; V Blank End
  322.         DW  nil         ; End of CRTC Data for 200/400 Lines
  323.  
  324. MODE_240_Tall:
  325. MODE_480_Tall:          ; CRTC Setup Data for 240/480 Line modes
  326.         DW  00D06H      ; Vertical Total
  327.         DW  03E07H      ; Overflow
  328.         DW  0EA10H      ; V Sync Start
  329.         DW  08C11H      ; V Sync End/Prot Cr0 Cr7
  330.         DW  0DF12H      ; Vertical Displayed
  331.         DW  0E715H      ; V Blank Start
  332.         DW  00616H      ; V Blank End
  333.         DW  nil         ; End of CRTC Data for 240/480 Lines
  334.  
  335.         ; Table of Display Mode Tables
  336.  
  337. MODE_TABLE:
  338.         DW  o MODE_320x200, o MODE_320x400
  339.         DW  o MODE_360x200, o MODE_360x400
  340.         DW  o MODE_320x240, o MODE_320x480
  341.         DW  o MODE_360x240, o MODE_360x480
  342.  
  343.         ; Table of Display Mode Components
  344.  
  345. MODE_320x200:           ; Data for 320 by 200 Pixels
  346.  
  347.         DB  063h        ; 400 scan Lines & 25 Mhz Clock
  348.         DB  4           ; Maximum of 4 Pages
  349.         DW  320, 200    ; Displayed Pixels (X,Y)
  350.         DW  1302, 816   ; Max Possible X and Y Sizes
  351.  
  352.         DW  o MODE_320_Wide, o MODE_200_Tall
  353.         DW  o MODE_Double_Line, nil
  354.  
  355. MODE_320x400:           ; Data for 320 by 400 Pixels
  356.  
  357.         DB  063h        ; 400 scan Lines & 25 Mhz Clock
  358.         DB  2           ; Maximum of 2 Pages
  359.         DW  320, 400    ; Displayed Pixels X,Y
  360.         DW  648, 816    ; Max Possible X and Y Sizes
  361.  
  362.         DW  o MODE_320_Wide, o MODE_400_Tall
  363.         DW  o MODE_Single_Line, nil
  364.  
  365. MODE_360x240:           ; Data for 360 by 240 Pixels
  366.  
  367.         DB  0E7h        ; 480 scan Lines & 28 Mhz Clock
  368.         DB  3           ; Maximum of 3 Pages
  369.         DW  360, 240    ; Displayed Pixels X,Y
  370.         DW  1092, 728   ; Max Possible X and Y Sizes
  371.  
  372.         DW  o MODE_360_Wide, o MODE_240_Tall
  373.         DW  o MODE_Double_Line , nil
  374.  
  375. MODE_360x480:           ; Data for 360 by 480 Pixels
  376.  
  377.         DB  0E7h        ; 480 scan Lines & 28 Mhz Clock
  378.         DB  1           ; Only 1 Page Possible
  379.         DW  360, 480    ; Displayed Pixels X,Y
  380.         DW  544, 728    ; Max Possible X and Y Sizes
  381.  
  382.         DW  o MODE_360_Wide, o MODE_480_Tall
  383.         DW  o MODE_Single_Line , nil
  384.  
  385. MODE_320x240:           ; Data for 320 by 240 Pixels
  386.  
  387.         DB  0E3h        ; 480 scan Lines & 25 Mhz Clock
  388.         DB  3           ; Maximum of 3 Pages
  389.         DW  320, 240    ; Displayed Pixels X,Y
  390.         DW  1088, 818   ; Max Possible X and Y Sizes
  391.  
  392.         DW  o MODE_320_Wide, o MODE_240_Tall
  393.         DW  o MODE_Double_Line, nil
  394.  
  395. MODE_320x480:           ; Data for 320 by 480 Pixels
  396.  
  397.         DB  0E3h        ; 480 scan Lines & 25 Mhz Clock
  398.         DB  1           ; Only 1 Page Possible
  399.         DW  320, 480    ; Displayed Pixels X,Y
  400.         DW  540, 818    ; Max Possible X and Y Sizes
  401.  
  402.         DW  o MODE_320_WIDE, o MODE_480_Tall
  403.         DW  o MODE_Single_Line, nil
  404.  
  405. MODE_360x200:           ; Data for 360 by 200 Pixels
  406.  
  407.         DB  067h        ; 400 scan Lines & 28 Mhz Clock
  408.         DB  3           ; Maximum of 3 Pages
  409.         DW  360, 200    ; Displayed Pixels (X,Y)
  410.         DW  1302, 728   ; Max Possible X and Y Sizes
  411.  
  412.         DW  o MODE_360_Wide, MODE_200_Tall
  413.         DW  o MODE_Double_Line, nil
  414.  
  415. MODE_360x400:           ; Data for 360 by 400 Pixels
  416.  
  417.         DB  067h        ; 400 scan Lines & 28 Mhz Clock
  418.         DB  1           ; Maximum of 1 Pages
  419.         DW  360, 400    ; Displayed Pixels X,Y
  420.         DW  648, 816    ; Max Possible X and Y Sizes
  421.  
  422.         DW  o MODE_360_Wide, MODE_400_Tall
  423.         DW  o MODE_Single_Line, nil
  424.  
  425.  
  426.     ; ===== MODE X SETUP ROUTINES =====
  427.  
  428. ;======================================================
  429. ;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)
  430. ;======================================================
  431. ;
  432. ; Sets Up the specified version of Mode X.  Allows for
  433. ; the setup of multiple video pages, and a virtual
  434. ; screen which can be larger than the displayed screen
  435. ; (which can then be scrolled a pixel at a time)
  436. ;
  437. ; ENTRY: ModeType = Desired Screen Resolution (0-7)
  438. ;
  439. ;     0 =  320 x 200, 4 Pages max,   1.2:1 Aspect Ratio
  440. ;     1 =  320 x 400, 2 Pages max,   2.4:1 Aspect Ratio
  441. ;     2 =  360 x 200, 3 Pages max,  1.35:1 Aspect Ratio
  442. ;     3 =  360 x 400, 1 Page  max,   2.7:1 Aspect Ratio
  443. ;     4 =  320 x 240, 3 Pages max,     1:1 Aspect Ratio
  444. ;     5 =  320 x 480, 1 Page  max,     2:1 Aspect Ratio
  445. ;     6 =  360 x 240, 3 Pages max, 1.125:1 Aspect Ratio
  446. ;     7 =  360 x 480, 1 Page  max,  2.25:1 Aspect Ratio
  447. ;
  448. ;        MaxXpos = The Desired Virtual Screen Width
  449. ;        MaxYpos = The Desired Virtual Screen Height
  450. ;        Pages   = The Desired # of Video Pages
  451. ;
  452. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  453. ;
  454.  
  455. SVM_STACK   STRUC
  456.     SVM_Table   DW  ?   ; Offset of Mode Info Table
  457.                 DW  ?x4 ; DI, SI, DS, BP
  458.                 DD  ?   ; Caller
  459.     SVM_Pages   DW  ?   ; # of Screen Pages desired
  460.     SVM_Ysize   DW  ?   ; Vertical Screen Size Desired
  461.     SVM_Xsize   DW  ?   ; Horizontal Screen Size Desired
  462.     SVM_Mode    DW  ?   ; Display Resolution Desired
  463. SVM_STACK   ENDS
  464.  
  465.     PUBLIC  SET_VGA_MODEX
  466.  
  467. SET_VGA_MODEX   PROC    FAR
  468.  
  469.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  470.     SUB     SP, 2               ; Allocate workspace
  471.     MOV     BP, SP              ; Set up Stack Frame
  472.  
  473.     ; Check Legality of Mode Request....
  474.  
  475.     MOV     BX, [BP].SVM_Mode   ; Get Requested Mode #
  476.     CMP     BX, NUM_MODES       ; Is it 0..7?
  477.     JAE     @SVM_BadModeSetup   ; If Not, Error out
  478.  
  479.     SHL     BX, 1                   ; Scale BX
  480.     MOV     SI, w MODE_TABLE[BX]    ; CS:SI -> Mode Info
  481.     MOV     [BP].SVM_Table, SI      ; Save ptr for later use
  482.  
  483.     ; Check # of Requested Display Pages
  484.  
  485.     MOV     CX, [BP].SVM_Pages  ; Get # of Requested Pages
  486.     CLR     CH                  ; Set Hi Word = 0!
  487.     CMP     CL, CS:[SI].M_Pages ; Check # Pages for mode
  488.     JA      @SVM_BadModeSetup   ; Report Error if too Many Pages
  489.     JCXZ    @SVM_BadModeSetup   ; Report Error if 0 Pages
  490.  
  491.     ; Check Validity of X Size
  492.  
  493.     AND     [BP].SVM_XSize, 0FFF8h  ; X size Mod 8 Must = 0
  494.  
  495.     MOV     AX, [BP].SVM_XSize  ; Get Logical Screen Width
  496.     CMP     AX, CS:[SI].M_XSize ; Check against Displayed X
  497.     JB      @SVM_BadModeSetup   ; Report Error if too small
  498.     CMP     AX, CS:[SI].M_XMax  ; Check against Max X
  499.     JA      @SVM_BadModeSetup   ; Report Error if too big
  500.  
  501.     ; Check Validity of Y Size
  502.  
  503.     MOV     BX, [BP].SVM_YSize  ; Get Logical Screen Height
  504.     CMP     BX, CS:[SI].M_YSize ; Check against Displayed Y
  505.     JB      @SVM_BadModeSetup   ; Report Error if too small
  506.     CMP     BX, CS:[SI].M_YMax  ; Check against Max Y
  507.     JA      @SVM_BadModeSetup   ; Report Error if too big
  508.  
  509.     ; Enough memory to Fit it all?
  510.  
  511.     SHR     AX, 2               ; # of Bytes:Line = XSize/4
  512.     MUL     CX                  ; AX = Bytes/Line * Pages
  513.     MUL     BX                  ; DX:AX = Total VGA mem needed
  514.     JNO     @SVM_Continue       ; Exit if Total Size > 256K
  515.  
  516.     DEC     DX                  ; Was it Exactly 256K???
  517.     OR      DX, AX              ; (DX = 1, AX = 0000)
  518.     JZ      @SVM_Continue       ; if so, it's valid...
  519.  
  520. @SVM_BadModeSetup:
  521.  
  522.     CLR     AX                  ; Return Value = False
  523.     JMP     @SVM_Exit           ; Normal Exit
  524.  
  525. @SVM_Continue:
  526.  
  527.     MOV     AX, 13H             ; Start with Mode 13H
  528.     INT     10H                 ; Let BIOS Set Mode
  529.  
  530.     OUT_16  SC_INDEX, CHAIN4_OFF            ; Disable Chain 4 Mode
  531.     OUT_16  SC_INDEX, ASYNC_RESET           ; (A)synchronous Reset
  532.     OUT_8   MISC_OUTPUT, CS:[SI].M_MiscR    ; Set New Timing/Size
  533.     OUT_16  SC_INDEX, SEQU_RESTART          ; Restart Sequencer ...
  534.  
  535.     OUT_8   CRTC_INDEX, 11H     ; Select Vert Retrace End Register
  536.     INC     DX                  ; Point to Data
  537.     IN      AL, DX              ; Get Value, Bit 7 = Protect
  538.     AND     AL, 7FH             ; Mask out Write Protect
  539.     OUT     DX, AL              ; And send it back
  540.  
  541.     MOV     DX, CRTC_INDEX      ; Vga Crtc Registers
  542.     ADD     SI, M_CRTC          ; SI -> CRTC Parameter Data
  543.  
  544.     ; Load Tables of CRTC Parameters from List of Tables
  545.  
  546. @SVM_Setup_Table:
  547.  
  548.     MOV     DI, CS:[SI]         ; Get Pointer to CRTC Data Tbl
  549.     ADD     SI, 2               ; Point to next Ptr Entry
  550.     OR      DI, DI              ; A nil Ptr means that we have
  551.     JZ      @SVM_Set_Data       ; finished CRTC programming
  552.  
  553. @SVM_Setup_CRTC:
  554.     MOV     AX, CS:[DI]         ; Get CRTC Data from Table
  555.     ADD     DI, 2               ; Advance Pointer
  556.     OR      AX, AX              ; At End of Data Table?
  557.     JZ      @SVM_Setup_Table    ; If so, Exit & get next Table
  558.  
  559.     OUT     DX, AX              ; Reprogram VGA CRTC reg
  560.     JMP     s @SVM_Setup_CRTC   ; Process Next Table Entry
  561.  
  562.     ; Initialize Page & Scroll info, DI = 0
  563.  
  564. @SVM_Set_Data:
  565.     MOV     DISPLAY_PAGE, DI    ; Display Page = 0
  566.     MOV     ACTIVE_PAGE, DI     ; Active Page = 0
  567.     MOV     CURRENT_PAGE, DI    ; Current Page (Offset) = 0
  568.     MOV     CURRENT_XOFFSET, DI ; Horz Scroll Index = 0
  569.     MOV     CURRENT_YOFFSET, DI ; Vert Scroll Index = 0
  570.     MOV     CURRENT_MOFFSET, DI ; Memory Scroll Index = 0
  571.  
  572.     MOV     AX, VGA_SEGMENT     ; Segment for VGA memory
  573.     MOV     CURRENT_SEGMENT, AX ; Save for Future LES's
  574.  
  575.     ; Set Logical Screen Width, X Scroll and Our Data
  576.  
  577.     MOV     SI, [BP].SVM_Table  ; Get Saved Ptr to Mode Info
  578.     MOV     AX, [BP].SVM_Xsize  ; Get Display Width
  579.  
  580.     MOV     CX, AX              ; CX = Logical Width
  581.     SUB     CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
  582.     MOV     MAX_XOFFSET, CX     ; Set Maximum X Scroll
  583.  
  584.     SHR     AX, 2               ; Bytes = Pixels / 4
  585.     MOV     SCREEN_WIDTH, AX    ; Save Width in Pixels
  586.  
  587.     SHR     AX, 1               ; Offset Value = Bytes / 2
  588.     MOV     AH, 13h             ; CRTC Offset Register Index
  589.     XCHG    AL, AH              ; Switch format for OUT
  590.     OUT     DX, AX              ; Set VGA CRTC Offset Reg
  591.  
  592.     ; Setup Data table, Y Scroll, Misc for Other Routines
  593.  
  594.     MOV     AX, [BP].SVM_Ysize  ; Get Logical Screen Height
  595.  
  596.     MOV     CX, AX              ; CX = Logical Height
  597.     SUB     BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
  598.     MOV     MAX_YOFFSET, CX     ; Set Maximum Y Scroll
  599.  
  600.     MOV     SCREEN_HEIGHT, AX   ; Save Height in Pixels
  601.     MUL     SCREEN_WIDTH        ; AX = Page Size in Bytes,
  602.     MOV     PAGE_SIZE, AX       ; Save Page Size
  603.  
  604.     MOV     CX, [BP].SVM_Pages  ; Get # of Pages
  605.     MOV     LAST_PAGE, CX       ; Save # of Pages
  606.  
  607.     CLR     BX                  ; Page # = 0
  608.     MOV     DX, BX              ; Page 0 Offset = 0
  609.  
  610. @SVM_Set_Pages:
  611.  
  612.     MOV     PAGE_ADDR[BX], DX   ; Set Page #(BX) Offset
  613.     ADD     BX, 2               ; Page#++
  614.     ADD     DX, AX              ; Compute Addr of Next Page
  615.     LOOPx   CX, @SVM_Set_Pages  ; Loop until all Pages Set
  616.  
  617.     ; Clear VGA Memory
  618.  
  619.     OUT_16  SC_INDEX, ALL_PLANES_ON ; Select All Planes
  620.     LES     DI, d CURRENT_PAGE      ; -> Start of VGA memory
  621.  
  622.     CLR     AX                  ; AX = 0
  623.     CLD                         ; Block Xfer Forwards
  624.     MOV     CX, 8000H           ; 32K * 4 * 2 = 256K
  625.     REP     STOSW               ; Clear dat memory!
  626.  
  627.     ; Setup Font Pointers
  628.  
  629.     MOV     BH, ROM_8x8_Lo      ; Ask for 8x8 Font, 0-127
  630.     MOV     AX, GET_CHAR_PTR    ; Service to Get Pointer
  631.     INT     10h                 ; Call VGA BIOS
  632.  
  633.     MOV     CHARSET_LOW, BP     ; Save Char Set Offset
  634.     MOV     CHARSET_LOW+2, ES   ; Save Char Set Segment
  635.  
  636.     MOV     BH, ROM_8x8_Hi      ; Ask for 8x8 Font, 128-255
  637.     MOV     AX, GET_CHAR_PTR    ; Service to Get Pointer
  638.     INT     10h                 ; Call VGA BIOS
  639.  
  640.     MOV     CHARSET_HI, BP      ; Save Char Set Offset
  641.     MOV     CHARSET_HI+2, ES    ; Save Char Set Segment
  642.  
  643.     MOV     AX, True            ; Return Success Code
  644.  
  645. @SVM_EXIT:
  646.     ADD     SP, 2               ; Deallocate workspace
  647.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  648.     RET     8                   ; Exit & Clean Up Stack
  649.  
  650. SET_VGA_MODEX   ENDP
  651.  
  652.  
  653. ;==================
  654. ;SET_MODEX% (Mode%)
  655. ;==================
  656. ;
  657. ; Quickie Mode Set - Sets Up Mode X to Default Configuration
  658. ;
  659. ; ENTRY: ModeType = Desired Screen Resolution (0-7)
  660. ;        (See SET_VGA_MODEX for list)
  661. ;
  662. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  663. ;
  664.  
  665. SM_STACK    STRUC
  666.                 DW  ?,? ; BP, SI
  667.                 DD  ?   ; Caller
  668.     SM_Mode     DW  ?   ; Desired Screen Resolution
  669. SM_STACK    ENDS
  670.  
  671.     PUBLIC  SET_MODEX
  672.  
  673. SET_MODEX   PROC    FAR
  674.  
  675.     PUSHx   BP, SI              ; Preserve Important registers
  676.     MOV     BP, SP              ; Set up Stack Frame
  677.  
  678.     CLR     AX                  ; Assume Failure
  679.     MOV     BX, [BP].SM_Mode    ; Get Desired Mode #
  680.     CMP     BX, NUM_MODES       ; Is it a Valid Mode #?
  681.     JAE     @SMX_Exit           ; If Not, don't Bother
  682.  
  683.     PUSH    BX                  ; Push Mode Parameter
  684.  
  685.     SHL     BX, 1                   ; Scale BX to word Index
  686.     MOV     SI, w MODE_TABLE[BX]    ; CS:SI -> Mode Info
  687.  
  688.     PUSH    CS:[SI].M_XSize     ; Push Default X Size
  689.     PUSH    CS:[SI].M_Ysize     ; Push Default Y size
  690.     MOV     AL, CS:[SI].M_Pages ; Get Default # of Pages
  691.     CLR     AH                  ; Hi Byte = 0
  692.     PUSH    AX                  ; Push # Pages
  693.  
  694.     CALL    f SET_VGA_MODEX     ; Set up Mode X!
  695.  
  696. @SMX_Exit:
  697.     POPx    SI, BP              ; Restore Registers
  698.     RET     2                   ; Exit & Clean Up Stack
  699.  
  700. SET_MODEX   ENDP
  701.  
  702.  
  703.     ; ===== BASIC GRAPHICS PRIMITIVES =====
  704.  
  705. ;============================
  706. ;CLEAR_VGA_SCREEN (ColorNum%)
  707. ;============================
  708. ;
  709. ; Clears the active display page
  710. ;
  711. ; ENTRY: ColorNum = Color Value to fill the page with
  712. ;
  713. ; EXIT:  No meaningful values returned
  714. ;
  715.  
  716. CVS_STACK   STRUC
  717.                 DW  ?,? ; DI, BP
  718.                 DD  ?   ; Caller
  719.     CVS_COLOR   DB  ?,? ; Color to Set Screen to
  720. CVS_STACK   ENDS
  721.  
  722.     PUBLIC  CLEAR_VGA_SCREEN
  723.  
  724. CLEAR_VGA_SCREEN    PROC    FAR
  725.  
  726.     PUSHx   BP, DI              ; Preserve Important Registers
  727.     MOV     BP, SP              ; Set up Stack Frame
  728.  
  729.     OUT_16  SC_INDEX, ALL_PLANES_ON ; Select All Planes
  730.     LES     DI, d CURRENT_PAGE      ; Point to Active VGA Page
  731.  
  732.     MOV     AL, [BP].CVS_COLOR  ; Get Color
  733.     MOV     AH, AL              ; Copy for Word Write
  734.     CLD                         ; Block fill Forwards
  735.  
  736.     MOV     CX, PAGE_SIZE       ; Get Size of Page
  737.     SHR     CX, 1               ; Divide by 2 for Words
  738.     REP     STOSW               ; Block Fill VGA memory
  739.  
  740.     POPx    DI, BP              ; Restore Saved Registers
  741.     RET     2                   ; Exit & Clean Up Stack
  742.  
  743. CLEAR_VGA_SCREEN    ENDP
  744.  
  745.  
  746. ;===================================
  747. ;SET_POINT (Xpos%, Ypos%, ColorNum%)
  748. ;===================================
  749. ;
  750. ; Plots a single Pixel on the active display page
  751. ;
  752. ; ENTRY: Xpos     = X position to plot pixel at
  753. ;        Ypos     = Y position to plot pixel at
  754. ;        ColorNum = Color to plot pixel with
  755. ;
  756. ; EXIT:  No meaningful values returned
  757. ;
  758.  
  759. SP_STACK    STRUC
  760.                 DW  ?,? ; BP, DI
  761.                 DD  ?   ; Caller
  762.     SETP_Color  DB  ?,? ; Color of Point to Plot
  763.     SETP_Ypos   DW  ?   ; Y pos of Point to Plot
  764.     SETP_Xpos   DW  ?   ; X pos of Point to Plot
  765. SP_STACK    ENDS
  766.  
  767.         PUBLIC SET_POINT
  768.  
  769. SET_POINT   PROC    FAR
  770.  
  771.     PUSHx   BP, DI              ; Preserve Registers
  772.     MOV     BP, SP              ; Set up Stack Frame
  773.  
  774.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  775.  
  776.     MOV     AX, [BP].SETP_Ypos  ; Get Line # of Pixel
  777.     MUL     SCREEN_WIDTH        ; Get Offset to Start of Line
  778.  
  779.     MOV     BX, [BP].SETP_Xpos  ; Get Xpos
  780.     MOV     CX, BX              ; Copy to extract Plane # from
  781.     SHR     BX, 2               ; X offset (Bytes) = Xpos/4
  782.     ADD     BX, AX              ; Offset = Width*Ypos + Xpos/4
  783.  
  784.     MOV     AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
  785.     AND     CL, PLANE_BITS      ; Get Plane Bits
  786.     SHL     AH, CL              ; Get Plane Select Value
  787.     OUT_16  SC_Index, AX        ; Select Plane
  788.  
  789.     MOV     AL,[BP].SETP_Color  ; Get Pixel Color
  790.     MOV     ES:[DI+BX], AL      ; Draw Pixel
  791.  
  792.     POPx    DI, BP              ; Restore Saved Registers
  793.     RET     6                   ; Exit and Clean up Stack
  794.  
  795. SET_POINT        ENDP
  796.  
  797.  
  798. ;==========================
  799. ;READ_POINT% (Xpos%, Ypos%)
  800. ;==========================
  801. ;
  802. ; Read the color of a pixel from the Active Display Page
  803. ;
  804. ; ENTRY: Xpos = X position of pixel to read
  805. ;        Ypos = Y position of pixel to read
  806. ;
  807. ; EXIT:  AX   = Color of Pixel at (Xpos, Ypos)
  808. ;
  809.  
  810. RP_STACK    STRUC
  811.             DW  ?,? ; BP, DI
  812.             DD  ?   ; Caller
  813.     RP_Ypos DW  ?   ; Y pos of Point to Read
  814.     RP_Xpos DW  ?   ; X pos of Point to Read
  815. RP_STACK    ENDS
  816.  
  817.         PUBLIC  READ_POINT
  818.  
  819. READ_POINT      PROC    FAR
  820.  
  821.     PUSHx   BP, DI              ; Preserve Registers
  822.     MOV     BP, SP              ; Set up Stack Frame
  823.  
  824.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  825.  
  826.     MOV     AX, [BP].RP_Ypos    ; Get Line # of Pixel
  827.     MUL     SCREEN_WIDTH        ; Get Offset to Start of Line
  828.  
  829.     MOV     BX, [BP].RP_Xpos    ; Get Xpos
  830.     MOV     CX, BX
  831.     SHR     BX, 2               ; X offset (Bytes) = Xpos/4
  832.     ADD     BX, AX              ; Offset = Width*Ypos + Xpos/4
  833.  
  834.     MOV     AL, READ_MAP        ; GC Read Mask Register
  835.     MOV     AH, CL              ; Get Xpos
  836.     AND     AH, PLANE_BITS      ; & mask out Plane #
  837.     OUT_16  GC_INDEX, AX        ; Select Plane to read in
  838.  
  839.     CLR     AH                  ; Clear Return Value Hi byte
  840.     MOV     AL, ES:[DI+BX]      ; Get Color of Pixel
  841.  
  842.     POPx    DI, BP              ; Restore Saved Registers
  843.     RET     4                   ; Exit and Clean up Stack
  844.  
  845. READ_POINT        ENDP
  846.  
  847.  
  848. ;======================================================
  849. ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
  850. ;======================================================
  851. ;
  852. ; Fills a rectangular block on the active display Page
  853. ;
  854. ; ENTRY: Xpos1    = Left X position of area to fill
  855. ;        Ypos1    = Top Y position of area to fill
  856. ;        Xpos2    = Right X position of area to fill
  857. ;        Ypos2    = Bottom Y position of area to fill
  858. ;        ColorNum = Color to fill area with
  859. ;
  860. ; EXIT:  No meaningful values returned
  861. ;
  862.  
  863. FB_STACK    STRUC
  864.                 DW  ?x4 ; DS, DI, SI, BP
  865.                 DD  ?   ; Caller
  866.     FB_Color    DB  ?,? ; Fill Color
  867.     FB_Ypos2    DW  ?   ; Y pos of Lower Right Pixel
  868.     FB_Xpos2    DW  ?   ; X pos of Lower Right Pixel
  869.     FB_Ypos1    DW  ?   ; Y pos of Upper Left Pixel
  870.     FB_Xpos1    DW  ?   ; X pos of Upper Left Pixel
  871. FB_STACK    ENDS
  872.  
  873.         PUBLIC    FILL_BLOCK
  874.  
  875. FILL_BLOCK  PROC    FAR
  876.  
  877.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  878.     MOV     BP, SP              ; Set up Stack Frame
  879.  
  880.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  881.     CLD                         ; Direction Flag = Forward
  882.  
  883.     OUT_8   SC_INDEX, MAP_MASK  ; Set up for Plane Select
  884.  
  885.     ; Validate Pixel Coordinates
  886.     ; If necessary, Swap so X1 <= X2, Y1 <= Y2
  887.  
  888.     MOV     AX, [BP].FB_Ypos1   ; AX = Y1   is Y1< Y2?
  889.     MOV     BX, [BP].FB_Ypos2   ; BX = Y2
  890.     CMP     AX, BX
  891.     JLE     @FB_NOSWAP1
  892.  
  893.     MOV     [BP].FB_Ypos1, BX   ; Swap Y1 and Y2 and save Y1
  894.     XCHG    AX, BX              ; on stack for future use
  895.  
  896. @FB_NOSWAP1:
  897.     SUB     BX, AX              ; Get Y width
  898.     INC     BX                  ; Add 1 to avoid 0 value
  899.     MOV     [BP].FB_Ypos2, BX   ; Save in Ypos2
  900.  
  901.     MUL     SCREEN_WIDTH        ; Mul Y1 by Bytes per Line
  902.     ADD     DI, AX              ; DI = Start of Line Y1
  903.  
  904.     MOV     AX, [BP].FB_Xpos1   ; Check X1 <= X2
  905.     MOV     BX, [BP].FB_Xpos2   ;
  906.     CMP     AX, BX
  907.     JLE     @FB_NOSWAP2         ; Skip Ahead if Ok
  908.  
  909.     MOV     [BP].FB_Xpos2, AX   ; Swap X1 AND X2 and save X2
  910.     XCHG    AX, BX              ; on stack for future use
  911.  
  912.     ; All our Input Values are in order, Now determine
  913.     ; How many full "bands" 4 pixels wide (aligned) there
  914.     ; are, and if there are partial bands (<4 pixels) on
  915.     ; the left and right edges.
  916.  
  917. @FB_NOSWAP2:
  918.     MOV     DX, AX              ; DX = X1 (Pixel Position)
  919.     SHR     DX, 2               ; DX/4 = Bytes into Line
  920.     ADD     DI, DX              ; DI = Addr of Upper-Left Corner
  921.  
  922.     MOV     CX, BX              ; CX = X2 (Pixel Position)
  923.     SHR     CX, 2               ; CX/4 = Bytes into Line
  924.  
  925.     CMP     DX, CX              ; Start and end in same band?
  926.     JNE     @FB_NORMAL          ; if not, check for l & r edges
  927.     JMP     @FB_ONE_BAND_ONLY   ; if so, then special processing
  928.  
  929. @FB_NORMAL:
  930.     SUB     CX, DX              ; CX = # bands -1
  931.     MOV     SI, AX              ; SI = PLANE#(X1)
  932.     AND     SI, PLANE_BITS      ; if Left edge is aligned then
  933.     JZ      @FB_L_PLANE_FLUSH   ; no special processing..
  934.  
  935.     ; Draw "Left Edge" vertical strip of 1-3 pixels...
  936.  
  937.     OUT_8   SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask
  938.  
  939.     MOV     SI, DI              ; SI = Copy of Start Addr (UL)
  940.  
  941.     MOV     DX, [BP].FB_Ypos2   ; Get # of Lines to draw
  942.     MOV     AL, [BP].FB_Color   ; Get Fill Color
  943.     MOV     BX, SCREEN_WIDTH    ; Get Vertical increment Value
  944.  
  945. @FB_LEFT_LOOP:
  946.     MOV     ES:[SI], AL         ; Fill in Left Edge Pixels
  947.     ADD     SI, BX              ; Point to Next Line (Below)
  948.     LOOPjz  DX, @FB_LEFT_CONT   ; Exit loop if all Lines Drawn
  949.  
  950.     MOV     ES:[SI], AL         ; Fill in Left Edge Pixels
  951.     ADD     SI, BX              ; Point to Next Line (Below)
  952.     LOOPx   DX, @FB_LEFT_LOOP   ; loop until left strip is drawn
  953.  
  954. @FB_LEFT_CONT:
  955.  
  956.     INC     DI                  ; Point to Middle (or Right) Block
  957.     DEC     CX                  ; Reset CX instead of JMP @FB_RIGHT
  958.  
  959. @FB_L_PLANE_FLUSH:
  960.     INC     CX                  ; Add in Left band to middle block
  961.  
  962.     ; DI = Addr of 1st middle Pixel (band) to fill
  963.     ; CX = # of Bands to fill -1
  964.  
  965. @FB_RIGHT:
  966.     MOV     SI, [BP].FB_Xpos2   ; Get Xpos2
  967.     AND     SI, PLANE_BITS      ; Get Plane values
  968.     CMP     SI, 0003            ; Plane = 3?
  969.     JE      @FB_R_EDGE_FLUSH    ; Hey, add to middle
  970.  
  971.     ; Draw "Right Edge" vertical strip of 1-3 pixels...
  972.  
  973.     OUT_8   SC_Data, Right_Clip_Mask[SI]    ; Right Edge Plane Mask
  974.  
  975.     MOV     SI, DI              ; Get Addr of Left Edge
  976.     ADD     SI, CX              ; Add Width-1 (Bands)
  977.     DEC     SI                  ; To point to top of Right Edge
  978.  
  979.     MOV     DX, [BP].FB_Ypos2   ; Get # of Lines to draw
  980.     MOV     AL, [BP].FB_Color   ; Get Fill Color
  981.     MOV     BX, SCREEN_WIDTH    ; Get Vertical increment Value
  982.  
  983. @FB_RIGHT_LOOP:
  984.     MOV     ES:[SI], AL         ; Fill in Right Edge Pixels
  985.     ADD     SI, BX              ; Point to Next Line (Below)
  986.     LOOPjz  DX, @FB_RIGHT_CONT  ; Exit loop if all Lines Drawn
  987.  
  988.     MOV     ES:[SI], AL         ; Fill in Right Edge Pixels
  989.     ADD     SI, BX              ; Point to Next Line (Below)
  990.     LOOPx   DX, @FB_RIGHT_LOOP  ; loop until left strip is drawn
  991.  
  992. @FB_RIGHT_CONT:
  993.  
  994.     DEC     CX                  ; Minus 1 for Middle bands
  995.     JZ      @FB_EXIT            ; Uh.. no Middle bands...
  996.  
  997. @FB_R_EDGE_FLUSH:
  998.  
  999.     ; DI = Addr of Upper Left block to fill
  1000.     ; CX = # of Bands to fill in (width)
  1001.  
  1002.     OUT_8   SC_Data, ALL_PLANES ; Write to All Planes
  1003.  
  1004.     MOV     DX, SCREEN_WIDTH    ; DX = DI Increment
  1005.     SUB     DX, CX              ;  = Screen_Width-# Planes Filled
  1006.  
  1007.     MOV     BX, CX              ; BX = Quick Refill for CX
  1008.     MOV     SI, [BP].FB_Ypos2   ; SI = # of Line to Fill
  1009.     MOV     AL, [BP].FB_Color   ; Get Fill Color
  1010.  
  1011. @FB_MIDDLE_LOOP:
  1012.     REP     STOSB               ; Fill in entire line
  1013.  
  1014.     MOV     CX, BX              ; Recharge CX (Line Width)
  1015.     ADD     DI, DX              ; Point to start of Next Line
  1016.     LOOPx   SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn
  1017.  
  1018.     JMP     s @FB_EXIT          ; Outa here
  1019.  
  1020. @FB_ONE_BAND_ONLY:
  1021.     MOV     SI, AX                  ; Get Left Clip Mask, Save X1
  1022.     AND     SI, PLANE_BITS          ; Mask out Row #
  1023.     MOV     AL, Left_Clip_Mask[SI]  ; Get Left Edge Mask
  1024.     MOV     SI, BX                  ; Get Right Clip Mask, Save X2
  1025.     AND     SI, PLANE_BITS          ; Mask out Row #
  1026.     AND     AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte
  1027.  
  1028.     OUT_8   SC_Data, AL         ; Clip For Left & Right Masks
  1029.  
  1030.     MOV     CX, [BP].FB_Ypos2   ; Get # of Lines to draw
  1031.     MOV     AL, [BP].FB_Color   ; Get Fill Color
  1032.     MOV     BX, SCREEN_WIDTH    ; Get Vertical increment Value
  1033.  
  1034. @FB_ONE_LOOP:
  1035.     MOV     ES:[DI], AL         ; Fill in Pixels
  1036.     ADD     DI, BX              ; Point to Next Line (Below)
  1037.     LOOPjz  CX, @FB_EXIT        ; Exit loop if all Lines Drawn
  1038.  
  1039.     MOV     ES:[DI], AL         ; Fill in Pixels
  1040.     ADD     DI, BX              ; Point to Next Line (Below)
  1041.     LOOPx   CX, @FB_ONE_LOOP    ; loop until left strip is drawn
  1042.  
  1043. @FB_EXIT:
  1044.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  1045.     RET     10                  ; Exit and Clean up Stack
  1046.  
  1047. FILL_BLOCK   ENDP
  1048.  
  1049.  
  1050. ;=====================================================
  1051. ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
  1052. ;=====================================================
  1053. ;
  1054. ; Draws a Line on the active display page
  1055. ;
  1056. ; ENTRY: Xpos1    = X position of first point on line
  1057. ;        Ypos1    = Y position of first point on line
  1058. ;        Xpos2    = X position of last point on line
  1059. ;        Ypos2    = Y position of last point on line
  1060. ;        ColorNum = Color to draw line with
  1061. ;
  1062. ; EXIT:  No meaningful values returned
  1063. ;
  1064.  
  1065. DL_STACK    STRUC
  1066.                 DW  ?x3 ; DI, SI, BP
  1067.                 DD  ?   ; Caller
  1068.     DL_ColorF   DB  ?,? ; Line Draw Color
  1069.     DL_Ypos2    DW  ?   ; Y pos of last point
  1070.     DL_Xpos2    DW  ?   ; X pos of last point
  1071.     DL_Ypos1    DW  ?   ; Y pos of first point
  1072.     DL_Xpos1    DW  ?   ; X pos of first point
  1073. DL_STACK    ENDS
  1074.  
  1075.         PUBLIC DRAW_LINE
  1076.  
  1077. DRAW_LINE   PROC    FAR
  1078.  
  1079.     PUSHx   BP, SI, DI          ; Preserve Important Registers
  1080.     MOV     BP, SP              ; Set up Stack Frame
  1081.     CLD                         ; Direction Flag = Forward
  1082.  
  1083.     OUT_8   SC_INDEX, MAP_MASK  ; Set up for Plane Select
  1084.     MOV     CH, [BP].DL_ColorF  ; Save Line Color in CH
  1085.  
  1086.     ; Check Line Type
  1087.  
  1088.     MOV     SI, [BP].DL_Xpos1   ; AX = X1   is X1< X2?
  1089.     MOV     DI, [BP].DL_Xpos2   ; DX = X2
  1090.     CMP     SI, DI              ; Is X1 < X2
  1091.     JE      @DL_VLINE           ; If X1=X2, Draw Vertical Line
  1092.     JL      @DL_NOSWAP1         ; If X1 < X2, don't swap
  1093.  
  1094.     XCHG    SI, DI              ; X2 IS > X1, SO SWAP THEM
  1095.  
  1096. @DL_NOSWAP1:
  1097.  
  1098.     ; SI = X1, DI = X2
  1099.  
  1100.     MOV     AX, [BP].DL_Ypos1   ; AX = Y1   is Y1 <> Y2?
  1101.     CMP     AX, [BP].DL_Ypos2   ; Y1 = Y2?
  1102.     JE      @DL_HORZ            ; If so, Draw a Horizontal Line
  1103.  
  1104.     JMP     @DL_BREZHAM         ; Diagonal line... go do it...
  1105.  
  1106.     ; This Code draws a Horizontal Line in Mode X where:
  1107.     ; SI = X1, DI = X2, and AX = Y1/Y2
  1108.  
  1109. @DL_HORZ:
  1110.  
  1111.     MUL     SCREEN_WIDTH        ; Offset = Ypos * Screen_Width
  1112.     MOV     DX, AX              ; CX = Line offset into Page
  1113.  
  1114.     MOV     AX, SI                  ; Get Left edge, Save X1
  1115.     AND     SI, PLANE_BITS          ; Mask out Row #
  1116.     MOV     BL, Left_Clip_Mask[SI]  ; Get Left Edge Mask
  1117.     MOV     CX, DI                  ; Get Right edge, Save X2
  1118.     AND     DI, PLANE_BITS          ; Mask out Row #
  1119.     MOV     BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte
  1120.  
  1121.     SHR     AX, 2               ; Get X1 Byte # (=X1/4)
  1122.     SHR     CX, 2               ; Get X2 Byte # (=X2/4)
  1123.  
  1124.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  1125.     ADD     DI, DX              ; Point to Start of Line
  1126.     ADD     DI, AX              ; Point to Pixel X1
  1127.  
  1128.     SUB     CX, AX              ; CX = # Of Bands (-1) to set
  1129.     JNZ     @DL_LONGLN          ; jump if longer than one segment
  1130.  
  1131.     AND     BL, BH              ; otherwise, merge clip masks
  1132.  
  1133. @DL_LONGLN:
  1134.  
  1135.     OUT_8   SC_Data, BL         ; Set the Left Clip Mask
  1136.  
  1137.     MOV     AL, [BP].DL_ColorF  ; Get Line Color
  1138.     MOV     BL, AL              ; BL = Copy of Line Color
  1139.     STOSB                       ; Set Left (1-4) Pixels
  1140.  
  1141.     JCXZ    @DL_EXIT            ; Done if only one Line Segment
  1142.  
  1143.     DEC     CX                  ; CX = # of Middle Segments
  1144.     JZ      @DL_XRSEG           ; If no middle segments....
  1145.  
  1146.     ; Draw Middle Segments
  1147.  
  1148.     OUT_8   DX, ALL_PLANES      ; Write to ALL Planes
  1149.  
  1150.     MOV     AL, BL              ; Get Color from BL
  1151.     REP     STOSB               ; Draw Middle (4 Pixel) Segments
  1152.  
  1153. @DL_XRSEG:
  1154.     OUT_8   DX, BH              ; Select Planes for Right Clip Mask
  1155.     MOV     AL, BL              ; Get Color Value
  1156.     STOSB                       ; Draw Right (1-4) Pixels
  1157.  
  1158.     JMP     s @DL_EXIT          ; We Are Done...
  1159.  
  1160.  
  1161.     ; This Code Draws A Vertical Line.  On entry:
  1162.     ; CH = Line Color, SI & DI = X1
  1163.  
  1164. @DL_VLINE:
  1165.  
  1166.     MOV     AX, [BP].DL_Ypos1   ; AX = Y1
  1167.     MOV     SI, [BP].DL_Ypos2   ; SI = Y2
  1168.     CMP     AX, SI              ; Is Y1 < Y2?
  1169.     JLE     @DL_NOSWAP2         ; if so, Don't Swap them
  1170.  
  1171.     XCHG    AX, SI              ; Ok, NOW Y1 < Y2
  1172.  
  1173. @DL_NOSWAP2:
  1174.  
  1175.     SUB     SI, AX              ; SI = Line Height (Y2-Y1+1)
  1176.     INC     SI
  1177.  
  1178.     ; AX = Y1, DI = X1, Get offset into Page into AX
  1179.  
  1180.     MUL     SCREEN_WIDTH        ; Offset = Y1 (AX) * Screen Width
  1181.     MOV     DX, DI              ; Copy Xpos into DX
  1182.     SHR     DI, 2               ; DI = Xpos/4
  1183.     ADD     AX, DI              ; DI = Xpos/4 + ScreenWidth * Y1
  1184.  
  1185.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  1186.     ADD     DI, AX              ; Point to Pixel X1, Y1
  1187.  
  1188.     ;Select Plane
  1189.  
  1190.     MOV     CL, DL              ; CL = Save X1
  1191.     AND     CL, PLANE_BITS      ; Get X1 MOD 4 (Plane #)
  1192.     MOV     AX, MAP_MASK_PLANE1 ; Code to set Plane #1
  1193.     SHL     AH, CL              ; Change to Correct Plane #
  1194.     OUT_16  SC_Index, AX        ; Select Plane
  1195.  
  1196.     MOV     AL, CH              ; Get Saved Color
  1197.     MOV     BX, SCREEN_WIDTH    ; Get Offset to Advance Line By
  1198.  
  1199. @DL_VLoop:
  1200.     MOV     ES:[DI], AL         ; Draw Single Pixel
  1201.     ADD     DI, BX              ; Point to Next Line
  1202.     LOOPjz  SI, @DL_EXIT        ; Lines--, Exit if done
  1203.  
  1204.     MOV     ES:[DI], AL         ; Draw Single Pixel
  1205.     ADD     DI, BX              ; Point to Next Line
  1206.     LOOPx   SI, @DL_VLoop       ; Lines--, Loop until Done
  1207.  
  1208. @DL_EXIT:
  1209.  
  1210.     JMP     @DL_EXIT2           ; Done!
  1211.  
  1212.     ; This code Draws a diagonal line in Mode X
  1213.  
  1214. @DL_BREZHAM:
  1215.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  1216.  
  1217.     MOV     AX, [BP].DL_Ypos1   ; get Y1 value
  1218.     MOV     BX, [BP].DL_Ypos2   ; get Y2 value
  1219.     MOV     CX, [BP].DL_Xpos1   ; Get Starting Xpos
  1220.  
  1221.     CMP     BX, AX              ; Y2-Y1 is?
  1222.     JNC     @DL_DeltaYOK        ; if Y2>=Y1 then goto...
  1223.  
  1224.     XCHG    BX, AX              ; Swap em...
  1225.     MOV     CX, [BP].DL_Xpos2   ; Get New Starting Xpos
  1226.  
  1227. @DL_DeltaYOK:
  1228.     MUL     SCREEN_WIDTH        ; Offset = SCREEN_WIDTH * Y1
  1229.  
  1230.     ADD     DI, AX              ; DI -> Start of Line Y1 on Page
  1231.     MOV     AX, CX              ; AX = Xpos (X1)
  1232.     SHR     AX, 2               ; /4 = Byte Offset into Line
  1233.     ADD     DI, AX              ; DI = Starting pos (X1,Y1)
  1234.  
  1235.     MOV     AL, 11h             ; Staring Mask
  1236.     AND     CL, PLANE_BITS      ; Get Plane #
  1237.     SHL     AL, CL              ; and shift into place
  1238.     MOV     AH, [BP].DL_ColorF  ; Color in Hi Bytes
  1239.  
  1240.     PUSH    AX                  ; Save Mask,Color...
  1241.  
  1242.     MOV     AH, AL              ; Plane # in AH
  1243.     MOV     AL, MAP_MASK        ; Select Plane Register
  1244.     OUT_16  SC_Index, AX        ; Select initial plane
  1245.  
  1246.     MOV     AX, [BP].DL_Xpos1   ; get X1 value
  1247.     MOV     BX, [BP].DL_Ypos1   ; get Y1 value
  1248.     MOV     CX, [BP].DL_Xpos2   ; get X2 value
  1249.     MOV     DX, [BP].DL_Ypos2   ; get Y2 value
  1250.  
  1251.     MOV     BP, SCREEN_WIDTH    ; Use BP for Line width to
  1252.                                 ; to avoid extra memory access
  1253.  
  1254.     SUB     DX, BX              ; figure Delta_Y
  1255.     JNC     @DL_DeltaYOK2       ; jump if Y2 >= Y1
  1256.  
  1257.     ADD     BX, DX              ; put Y2 into Y1
  1258.     NEG     DX                  ; abs(Delta_Y)
  1259.     XCHG    AX, CX              ; and exchange X1 and X2
  1260.  
  1261. @DL_DeltaYOK2:
  1262.     MOV     BX, 08000H          ; seed for fraction accumulator
  1263.  
  1264.     SUB     CX, AX              ; figure Delta_X
  1265.     JC      @DL_DrawLeft        ; if negative, go left
  1266.  
  1267.     JMP     @DL_DrawRight       ; Draw Line that slopes right
  1268.  
  1269. @DL_DrawLeft:
  1270.  
  1271.     NEG     CX                  ; abs(Delta_X)
  1272.  
  1273.     CMP     CX, DX              ; is Delta_X < Delta_Y?
  1274.     JB      @DL_SteepLeft       ; yes, so go do steep line
  1275.                                 ; (Delta_Y iterations)
  1276.  
  1277.     ; Draw a Shallow line to the left in Mode X
  1278.  
  1279. @DL_ShallowLeft:
  1280.     CLR     AX                  ; zero low word of Delta_Y * 10000h
  1281.     SUB     AX, DX              ; DX:AX <- DX * 0FFFFh
  1282.     SBB     DX, 0               ; include carry
  1283.     DIV     CX                  ; divide by Delta_X
  1284.  
  1285.     MOV     SI, BX              ; SI = Accumulator
  1286.     MOV     BX, AX              ; BX = Add fraction
  1287.     POP     AX                  ; Get Color, Bit mask
  1288.     MOV     DX, SC_Data         ; Sequence controller data register
  1289.     INC     CX                  ; Inc Delta_X so we can unroll loop
  1290.  
  1291.     ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
  1292.  
  1293. @DL_SLLLoop:
  1294.     MOV     ES:[DI], AH         ; set first pixel, plane data set up
  1295.     LOOPjz  CX, @DL_SLLExit     ; Delta_X--, Exit if done
  1296.  
  1297.     ADD     SI, BX              ; add numerator to accumulator
  1298.     JNC     @DL_SLLL2nc         ; move down on carry
  1299.  
  1300.     ADD     DI, BP              ; Move Down one line...
  1301.  
  1302. @DL_SLLL2nc:
  1303.     DEC     DI                  ; Left one addr
  1304.     ROR     AL, 1               ; Move Left one plane, back on 0 1 2
  1305.     CMP     AL, 87h             ; wrap?, if AL <88 then Carry set
  1306.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1307.     OUT     DX, AL              ; Set up New Bit Plane mask
  1308.  
  1309.     MOV     ES:[DI], AH         ; set pixel
  1310.     LOOPjz  CX, @DL_SLLExit     ; Delta_X--, Exit if done
  1311.  
  1312.     ADD     SI, BX              ; add numerator to accumulator,
  1313.     JNC     @DL_SLLL3nc         ; move down on carry
  1314.  
  1315.     ADD     DI, BP              ; Move Down one line...
  1316.  
  1317. @DL_SLLL3nc:                    ; Now move left a pixel...
  1318.     DEC     DI                  ; Left one addr
  1319.     ROR     AL, 1               ; Move Left one plane, back on 0 1 2
  1320.     CMP     AL, 87h             ; Wrap?, if AL <88 then Carry set
  1321.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1322.     OUT     DX, AL              ; Set up New Bit Plane mask
  1323.     JMP     s @DL_SLLLoop       ; loop until done
  1324.  
  1325. @DL_SLLExit:
  1326.     JMP     @DL_EXIT2           ; and exit
  1327.  
  1328.     ; Draw a steep line to the left in Mode X
  1329.  
  1330. @DL_SteepLeft:
  1331.     CLR     AX                  ; zero low word of Delta_Y * 10000h
  1332.     XCHG    DX, CX              ; Delta_Y switched with Delta_X
  1333.     DIV     CX                  ; divide by Delta_Y
  1334.  
  1335.     MOV     SI, BX              ; SI = Accumulator
  1336.     MOV     BX, AX              ; BX = Add Fraction
  1337.     POP     AX                  ; Get Color, Bit mask
  1338.     MOV     DX, SC_Data         ; Sequence controller data register
  1339.     INC     CX                  ; Inc Delta_Y so we can unroll loop
  1340.  
  1341.     ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
  1342.  
  1343. @DL_STLLoop:
  1344.  
  1345.     MOV     ES:[DI], AH         ; set first pixel
  1346.     LOOPjz  CX, @DL_STLExit     ; Delta_Y--, Exit if done
  1347.  
  1348.     ADD     SI, BX              ; add numerator to accumulator
  1349.     JNC     @DL_STLnc2          ; No carry, just move down!
  1350.  
  1351.     DEC     DI                  ; Move Left one addr
  1352.     ROR     AL, 1               ; Move Left one plane, back on 0 1 2
  1353.     CMP     AL, 87h             ; Wrap?, if AL <88 then Carry set
  1354.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1355.     OUT     DX, AL              ; Set up New Bit Plane mask
  1356.  
  1357. @DL_STLnc2:
  1358.     ADD     DI, BP              ; advance to next line.
  1359.  
  1360.     MOV     ES:[DI], AH         ; set pixel
  1361.     LOOPjz  CX, @DL_STLExit     ; Delta_Y--, Exit if done
  1362.  
  1363.     ADD     SI, BX              ; add numerator to accumulator
  1364.     JNC     @DL_STLnc3          ; No carry, just move down!
  1365.  
  1366.     DEC     DI                  ; Move Left one addr
  1367.     ROR     AL, 1               ; Move Left one plane, back on 0 1 2
  1368.     CMP     AL, 87h             ; Wrap?, if AL <88 then Carry set
  1369.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1370.     OUT     DX, AL              ; Set up New Bit Plane mask
  1371.  
  1372. @DL_STLnc3:
  1373.     ADD     DI, BP              ; advance to next line.
  1374.     JMP     s @DL_STLLoop       ; Loop until done
  1375.  
  1376. @DL_STLExit:
  1377.     JMP     @DL_EXIT2           ; and exit
  1378.  
  1379.     ; Draw a line that goes to the Right...
  1380.  
  1381. @DL_DrawRight:
  1382.     CMP     CX, DX              ; is Delta_X < Delta_Y?
  1383.     JB      @DL_SteepRight      ; yes, so go do steep line
  1384.                                 ; (Delta_Y iterations)
  1385.  
  1386.     ; Draw a Shallow line to the Right in Mode X
  1387.  
  1388. @DL_ShallowRight:
  1389.     CLR     AX                  ; zero low word of Delta_Y * 10000h
  1390.     SUB     AX, DX              ; DX:AX <- DX * 0FFFFh
  1391.     SBB     DX, 0               ; include carry
  1392.     DIV     CX                  ; divide by Delta_X
  1393.  
  1394.     MOV     SI, BX              ; SI = Accumulator
  1395.     MOV     BX, AX              ; BX = Add Fraction
  1396.     POP     AX                  ; Get Color, Bit mask
  1397.     MOV     DX, SC_Data         ; Sequence controller data register
  1398.     INC     CX                  ; Inc Delta_X so we can unroll loop
  1399.  
  1400.     ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
  1401.  
  1402. @DL_SLRLoop:
  1403.     MOV     ES:[DI], AH         ; set first pixel, mask is set up
  1404.     LOOPjz  CX, @DL_SLRExit     ; Delta_X--, Exit if done..
  1405.  
  1406.     ADD     SI, BX              ; add numerator to accumulator
  1407.     JNC     @DL_SLR2nc          ; don't move down if carry not set
  1408.  
  1409.     ADD     DI, BP              ; Move Down one line...
  1410.  
  1411. @DL_SLR2nc:                     ; Now move right a pixel...
  1412.     ROL     AL, 1               ; Move Right one addr if Plane = 0
  1413.     CMP     AL, 12h             ; Wrap? if AL >12 then Carry not set
  1414.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1415.     OUT     DX, AL              ; Set up New Bit Plane mask
  1416.  
  1417.     MOV     ES:[DI], AH         ; set pixel
  1418.     LOOPjz  CX, @DL_SLRExit     ; Delta_X--, Exit if done..
  1419.  
  1420.     ADD     SI, BX              ; add numerator to accumulator
  1421.     JNC     @DL_SLR3nc          ; don't move down if carry not set
  1422.  
  1423.     ADD     DI, BP              ; Move Down one line...
  1424.  
  1425. @DL_SLR3nc:
  1426.     ROL     AL, 1               ; Move Right one addr if Plane = 0
  1427.     CMP     AL, 12h             ; Wrap? if AL >12 then Carry not set
  1428.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1429.     OUT     DX, AL              ; Set up New Bit Plane mask
  1430.     JMP     s @DL_SLRLoop       ; loop till done
  1431.  
  1432. @DL_SLRExit:
  1433.     JMP     @DL_EXIT2           ; and exit
  1434.  
  1435.     ; Draw a Steep line to the Right in Mode X
  1436.  
  1437. @DL_SteepRight:
  1438.     CLR     AX                  ; zero low word of Delta_Y * 10000h
  1439.     XCHG    DX, CX              ; Delta_Y switched with Delta_X
  1440.     DIV     CX                  ; divide by Delta_Y
  1441.  
  1442.     MOV     SI, BX              ; SI = Accumulator
  1443.     MOV     BX, AX              ; BX = Add Fraction
  1444.     POP     AX                  ; Get Color, Bit mask
  1445.     MOV     DX, SC_Data         ; Sequence controller data register
  1446.     INC     CX                  ; Inc Delta_Y so we can unroll loop
  1447.  
  1448.     ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
  1449.  
  1450. @STRLoop:
  1451.     MOV     ES:[DI], AH         ; set first pixel, mask is set up
  1452.     LOOPjz  CX, @DL_EXIT2       ; Delta_Y--, Exit if Done
  1453.  
  1454.     ADD     SI, BX              ; add numerator to accumulator
  1455.     JNC     @STRnc2             ; if no carry then just go down...
  1456.  
  1457.     ROL     AL, 1               ; Move Right one addr if Plane = 0
  1458.     CMP     AL, 12h             ; Wrap? if AL >12 then Carry not set
  1459.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1460.     OUT     DX, AL              ; Set up New Bit Plane mask
  1461.  
  1462. @STRnc2:
  1463.     ADD     DI, BP              ; advance to next line.
  1464.  
  1465.     MOV     ES:[DI], AH         ; set pixel
  1466.     LOOPjz  CX, @DL_EXIT2       ; Delta_Y--, Exit if Done
  1467.  
  1468.     ADD     SI, BX              ; add numerator to accumulator
  1469.     JNC     @STRnc3             ; if no carry then just go down...
  1470.  
  1471.     ROL     AL, 1               ; Move Right one addr if Plane = 0
  1472.     CMP     AL, 12h             ; Wrap? if AL >12 then Carry not set
  1473.     ADC     DI, 0               ; Adjust Address: DI = DI + Carry
  1474.     OUT     DX, AL              ; Set up New Bit Plane mask
  1475.  
  1476. @STRnc3:
  1477.     ADD     DI, BP              ; advance to next line.
  1478.     JMP     s @STRLoop          ; loop till done
  1479.  
  1480. @DL_EXIT2:
  1481.     POPx    DI, SI, BP          ; Restore Saved Registers
  1482.     RET     10                  ; Exit and Clean up Stack
  1483.  
  1484. DRAW_LINE        ENDP
  1485.  
  1486.  
  1487.     ; ===== DAC COLOR REGISTER ROUTINES =====
  1488.  
  1489. ;=================================================
  1490. ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
  1491. ;=================================================
  1492. ;
  1493. ; Sets a single (RGB) Vga Palette Register
  1494. ;
  1495. ; ENTRY: Register = The DAC # to modify (0-255)
  1496. ;        Red      = The new Red Intensity (0-63)
  1497. ;        Green    = The new Green Intensity (0-63)
  1498. ;        Blue     = The new Blue Intensity (0-63)
  1499. ;
  1500. ; EXIT:  No meaningful values returned
  1501. ;
  1502.  
  1503. SDR_STACK   STRUC
  1504.                     DW  ?   ; BP
  1505.                     DD  ?   ; Caller
  1506.     SDR_Blue        DB  ?,? ; Blue Data Value
  1507.     SDR_Green       DB  ?,? ; Green Data Value
  1508.     SDR_Red         DB  ?,? ; Red Data Value
  1509.     SDR_Register    DB  ?,? ; Palette Register #
  1510. SDR_STACK   ENDS
  1511.  
  1512.     PUBLIC  SET_DAC_REGISTER
  1513.  
  1514. SET_DAC_REGISTER    PROC    FAR
  1515.  
  1516.     PUSH    BP                  ; Save BP
  1517.     MOV     BP, SP              ; Set up Stack Frame
  1518.  
  1519.     ; Select which DAC Register to modify
  1520.  
  1521.     OUT_8   DAC_WRITE_ADDR, [BP].SDR_Register
  1522.  
  1523.     MOV     DX, PEL_DATA_REG    ; Dac Data Register
  1524.     OUT_8   DX, [BP].SDR_Red    ; Set Red Intensity
  1525.     OUT_8   DX, [BP].SDR_Green  ; Set Green Intensity
  1526.     OUT_8   DX, [BP].SDR_Blue   ; Set Blue Intensity
  1527.  
  1528.     POP     BP                  ; Restore Registers
  1529.     RET     8                   ; Exit & Clean Up Stack
  1530.  
  1531. SET_DAC_REGISTER    ENDP
  1532.  
  1533. ;====================================================
  1534. ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
  1535. ;====================================================
  1536. ;
  1537. ; Reads the RGB Values of a single Vga Palette Register
  1538. ;
  1539. ; ENTRY: Register = The DAC # to read (0-255)
  1540. ;        Red      = Offset to Red Variable in DS
  1541. ;        Green    = Offset to Green Variable in DS
  1542. ;        Blue     = Offset to Blue Variable in DS
  1543. ;
  1544. ; EXIT:  The values of the integer variables Red,
  1545. ;        Green, and Blue are set to the values
  1546. ;        taken from the specified DAC register.
  1547. ;
  1548.  
  1549. GDR_STACK   STRUC
  1550.                     DW  ?   ; BP
  1551.                     DD  ?   ; Caller
  1552.     GDR_Blue        DW  ?   ; Addr of Blue Data Value in DS
  1553.     GDR_Green       DW  ?   ; Addr of Green Data Value in DS
  1554.     GDR_Red         DW  ?   ; Addr of Red Data Value in DS
  1555.     GDR_Register    DB  ?,? ; Palette Register #
  1556. GDR_STACK   ENDS
  1557.  
  1558.     PUBLIC  GET_DAC_REGISTER
  1559.  
  1560. GET_DAC_REGISTER    PROC    FAR
  1561.  
  1562.     PUSH    BP                  ; Save BP
  1563.     MOV     BP, SP              ; Set up Stack Frame
  1564.  
  1565.     ; Select which DAC Register to read in
  1566.  
  1567.     OUT_8   DAC_READ_ADDR, [BP].GDR_Register
  1568.  
  1569.     MOV     DX, PEL_DATA_REG    ; Dac Data Register
  1570.     CLR     AX                  ; Clear AX
  1571.  
  1572.     IN      AL, DX              ; Read Red Value
  1573.     MOV     BX, [BP].GDR_Red    ; Get Address of Red%
  1574.     MOV     [BX], AX            ; *Red% = AX
  1575.  
  1576.     IN      AL, DX              ; Read Green Value
  1577.     MOV     BX, [BP].GDR_Green  ; Get Address of Green%
  1578.     MOV     [BX], AX            ; *Green% = AX
  1579.  
  1580.     IN      AL, DX              ; Read Blue Value
  1581.     MOV     BX, [BP].GDR_Blue   ; Get Address of Blue%
  1582.     MOV     [BX], AX            ; *Blue% = AX
  1583.  
  1584.     POP     BP                  ; Restore Registers
  1585.     RET     8                   ; Exit & Clean Up Stack
  1586.  
  1587. GET_DAC_REGISTER    ENDP
  1588.  
  1589.  
  1590. ;===========================================================
  1591. ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)
  1592. ;===========================================================
  1593. ;
  1594. ; Sets a Block of Vga Palette Registers
  1595. ;
  1596. ; ENTRY: PalData  = Far Pointer to Block of palette data
  1597. ;        StartReg = First Register # in range to set (0-255)
  1598. ;        EndReg   = Last Register # in Range to set (0-255)
  1599. ;        Sync     = Wait for Vertical Retrace Flag (Boolean)
  1600. ;
  1601. ; EXIT:  No meaningful values returned
  1602. ;
  1603. ; NOTES: PalData is a linear array of 3 byte Palette values
  1604. ;        in the order: Red  (0-63), Green (0-63), Blue (0-63)
  1605. ;
  1606.  
  1607. LDR_STACK   STRUC
  1608.                     DW  ?x3 ; BP, DS, SI
  1609.                     DD  ?   ; Caller
  1610.     LDR_Sync        DW  ?   ; Vertical Sync Flag
  1611.     LDR_EndReg      DB  ?,? ; Last Register #
  1612.     LDR_StartReg    DB  ?,? ; First Register #
  1613.     LDR_PalData     DD  ?   ; Far Ptr to Palette Data
  1614. LDR_STACK   ENDS
  1615.  
  1616.     PUBLIC  LOAD_DAC_REGISTERS
  1617.  
  1618. LOAD_DAC_REGISTERS  PROC    FAR
  1619.  
  1620.     PUSHx   BP, DS, SI          ; Save Registers
  1621.     mov     BP, SP              ; Set up Stack Frame
  1622.  
  1623.     mov     AX, [BP].LDR_Sync   ; Get Vertical Sync Flag
  1624.     or      AX, AX              ; is Sync Flag = 0?
  1625.     jz      @LDR_Load           ; if so, skip call
  1626.  
  1627.     call    f SYNC_DISPLAY      ; wait for vsync
  1628.  
  1629.     ; Determine register #'s, size to copy, etc
  1630.  
  1631. @LDR_Load:
  1632.  
  1633.     lds     SI, [BP].LDR_PalData    ; DS:SI -> Palette Data
  1634.     mov     DX, DAC_WRITE_ADDR      ; DAC register # selector
  1635.  
  1636.     CLR     AX, BX                  ; Clear for byte loads
  1637.     mov     AL, [BP].LDR_StartReg   ; Get Start Register
  1638.     mov     BL, [BP].LDR_EndReg     ; Get End Register
  1639.  
  1640.     sub     BX, AX              ; BX = # of DAC registers -1
  1641.     inc     BX                  ; BX = # of DAC registers
  1642.     mov     CX, BX              ; CX = # of DAC registers
  1643.     add     CX, BX              ; CX =  "   " * 2
  1644.     add     CX, BX              ; CX =  "   " * 3
  1645.     cld                         ; Block OUTs forward
  1646.     out     DX, AL              ; set up correct register #
  1647.  
  1648.     ; Load a block of DAC Registers
  1649.  
  1650.     mov     DX, PEL_DATA_REG    ; Dac Data Register
  1651.  
  1652.     rep     outsb               ; block set DAC registers
  1653.  
  1654.     POPx    SI, DS, BP          ; Restore Registers
  1655.     ret     10                  ; Exit & Clean Up Stack
  1656.  
  1657. LOAD_DAC_REGISTERS  ENDP
  1658.  
  1659.  
  1660. ;====================================================
  1661. ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)
  1662. ;====================================================
  1663. ;
  1664. ; Reads a Block of Vga Palette Registers
  1665. ;
  1666. ; ENTRY: PalData  = Far Pointer to block to store palette data
  1667. ;        StartReg = First Register # in range to read (0-255)
  1668. ;        EndReg   = Last Register # in Range to read (0-255)
  1669. ;
  1670. ; EXIT:  No meaningful values returned
  1671. ;
  1672. ; NOTES: PalData is a linear array of 3 byte Palette values
  1673. ;        in the order: Red  (0-63), Green (0-63), Blue (0-63)
  1674. ;
  1675.  
  1676. RDR_STACK   STRUC
  1677.                     DW  ?x3 ; BP, ES, DI
  1678.                     DD  ?   ; Caller
  1679.     RDR_EndReg      DB  ?,? ; Last Register #
  1680.     RDR_StartReg    DB  ?,? ; First Register #
  1681.     RDR_PalData     DD  ?   ; Far Ptr to Palette Data
  1682. RDR_STACK   ENDS
  1683.  
  1684.     PUBLIC  READ_DAC_REGISTERS
  1685.  
  1686. READ_DAC_REGISTERS  PROC    FAR
  1687.  
  1688.     PUSHx   BP, ES, DI          ; Save Registers
  1689.     mov     BP, SP              ; Set up Stack Frame
  1690.  
  1691.     ; Determine register #'s, size to copy, etc
  1692.  
  1693.     les     DI, [BP].RDR_PalData    ; ES:DI -> Palette Buffer
  1694.     mov     DX, DAC_READ_ADDR       ; DAC register # selector
  1695.  
  1696.     CLR     AX, BX                  ; Clear for byte loads
  1697.     mov     AL, [BP].RDR_StartReg   ; Get Start Register
  1698.     mov     BL, [BP].RDR_EndReg     ; Get End Register
  1699.  
  1700.     sub     BX, AX              ; BX = # of DAC registers -1
  1701.     inc     BX                  ; BX = # of DAC registers
  1702.     mov     CX, BX              ; CX = # of DAC registers
  1703.     add     CX, BX              ; CX =  "   " * 2
  1704.     add     CX, BX              ; CX =  "   " * 3
  1705.     cld                         ; Block INs forward
  1706.  
  1707.     ; Read a block of DAC Registers
  1708.  
  1709.     out     DX, AL              ; set up correct register #
  1710.     mov     DX, PEL_DATA_REG    ; Dac Data Register
  1711.  
  1712.     rep     insb                ; block read DAC registers
  1713.  
  1714.     POPx    DI, ES, BP          ; Restore Registers
  1715.     ret     8                   ; Exit & Clean Up Stack
  1716.  
  1717. READ_DAC_REGISTERS  ENDP
  1718.  
  1719.  
  1720.     ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
  1721.  
  1722. ;=========================
  1723. ;SET_ACTIVE_PAGE (PageNo%)
  1724. ;=========================
  1725. ;
  1726. ; Sets the active display Page to be used for future drawing
  1727. ;
  1728. ; ENTRY: PageNo = Display Page to make active
  1729. ;        (values: 0 to Number of Pages - 1)
  1730. ;
  1731. ; EXIT:  No meaningful values returned
  1732. ;
  1733.  
  1734. SAP_STACK   STRUC
  1735.                 DW  ?   ; BP
  1736.                 DD  ?   ; Caller
  1737.     SAP_Page    DW  ?   ; Page # for Drawing
  1738. SAP_STACK   ENDS
  1739.  
  1740.     PUBLIC  SET_ACTIVE_PAGE
  1741.  
  1742. SET_ACTIVE_PAGE PROC    FAR
  1743.  
  1744.     PUSH    BP                  ; Preserve Registers
  1745.     MOV     BP, SP              ; Set up Stack Frame
  1746.  
  1747.     MOV     BX, [BP].SAP_Page   ; Get Desired Page #
  1748.     CMP     BX, LAST_PAGE       ; Is Page # Valid?
  1749.     JAE     @SAP_Exit           ; IF Not, Do Nothing
  1750.  
  1751.     MOV     ACTIVE_PAGE, BX     ; Set Active Page #
  1752.  
  1753.     SHL     BX, 1               ; Scale Page # to Word
  1754.     MOV     AX, PAGE_ADDR[BX]   ; Get offset to Page
  1755.  
  1756.     MOV     CURRENT_PAGE, AX    ; And set for future LES's
  1757.  
  1758. @SAP_Exit:
  1759.     POP     BP                  ; Restore Registers
  1760.     RET     2                   ; Exit and Clean up Stack
  1761.  
  1762. SET_ACTIVE_PAGE ENDP
  1763.  
  1764.  
  1765. ;================
  1766. ;GET_ACTIVE_PAGE%
  1767. ;================
  1768. ;
  1769. ; Returns the Video Page # currently used for Drawing
  1770. ;
  1771. ; ENTRY: No Parameters are passed
  1772. ;
  1773. ; EXIT:  AX = Current Video Page used for Drawing
  1774. ;
  1775.  
  1776.     PUBLIC  GET_ACTIVE_PAGE
  1777.  
  1778. GET_ACTIVE_PAGE PROC    FAR
  1779.  
  1780.     MOV     AX, ACTIVE_PAGE     ; Get Active Page #
  1781.     RET                         ; Exit and Clean up Stack
  1782.  
  1783. GET_ACTIVE_PAGE ENDP
  1784.  
  1785.  
  1786. ;===============================
  1787. ;SET_DISPLAY_PAGE (DisplayPage%)
  1788. ;===============================
  1789. ;
  1790. ; Sets the currently visible display page.
  1791. ; When called this routine syncronizes the display
  1792. ; to the vertical blank.
  1793. ;
  1794. ; ENTRY: PageNo = Display Page to show on the screen
  1795. ;        (values: 0 to Number of Pages - 1)
  1796. ;
  1797. ; EXIT:  No meaningful values returned
  1798. ;
  1799.  
  1800. SDP_STACK   STRUC
  1801.                 DW  ?       ; BP
  1802.                 DD  ?       ; Caller
  1803.     SDP_Page    DW  ?       ; Page # to Display...
  1804. SDP_STACK   ENDS
  1805.  
  1806.     PUBLIC  SET_DISPLAY_PAGE
  1807.  
  1808. SET_DISPLAY_PAGE    PROC    FAR
  1809.  
  1810.     PUSH    BP                  ; Preserve Registers
  1811.     MOV     BP, SP              ; Set up Stack Frame
  1812.  
  1813.     MOV     BX, [BP].SDP_Page   ; Get Desired Page #
  1814.     CMP     BX, LAST_PAGE       ; Is Page # Valid?
  1815.     JAE     @SDP_Exit           ; IF Not, Do Nothing
  1816.  
  1817.     MOV     DISPLAY_PAGE, BX    ; Set Display Page #
  1818.  
  1819.     SHL     BX, 1               ; Scale Page # to Word
  1820.     MOV     CX, PAGE_ADDR[BX]   ; Get offset in memory to Page
  1821.     ADD     CX, CURRENT_MOFFSET ; Adjust for any scrolling
  1822.  
  1823.     ; Wait if we are currently in a Vertical Retrace
  1824.  
  1825.     MOV     DX, INPUT_1         ; Input Status #1 Register
  1826.  
  1827. @DP_WAIT0:
  1828.     IN      AL, DX              ; Get VGA status
  1829.     AND     AL, VERT_RETRACE    ; In Display mode yet?
  1830.     JNZ     @DP_WAIT0           ; If Not, wait for it
  1831.  
  1832.     ; Set the Start Display Address to the new page
  1833.  
  1834.     MOV     DX, CRTC_Index      ; We Change the VGA Sequencer
  1835.  
  1836.     MOV     AL, START_DISP_LO   ; Display Start Low Register
  1837.     MOV     AH, CL              ; Low 8 Bits of Start Addr
  1838.     OUT     DX, AX              ; Set Display Addr Low
  1839.  
  1840.     MOV     AL, START_DISP_HI   ; Display Start High Register
  1841.     MOV     AH, CH              ; High 8 Bits of Start Addr
  1842.     OUT     DX, AX              ; Set Display Addr High
  1843.  
  1844.     ; Wait for a Vertical Retrace to smooth out things
  1845.  
  1846.     MOV     DX, INPUT_1         ; Input Status #1 Register
  1847.  
  1848. @DP_WAIT1:
  1849.     IN      AL, DX              ; Get VGA status
  1850.     AND     AL, VERT_RETRACE    ; Vertical Retrace Start?
  1851.     JZ      @DP_WAIT1           ; If Not, wait for it
  1852.  
  1853.     ; Now Set Display Starting Address
  1854.  
  1855.  
  1856. @SDP_Exit:
  1857.     POP     BP                  ; Restore Registers
  1858.     RET     2                   ; Exit and Clean up Stack
  1859.  
  1860. SET_DISPLAY_PAGE    ENDP
  1861.  
  1862.  
  1863. ;=================
  1864. ;GET_DISPLAY_PAGE%
  1865. ;=================
  1866. ;
  1867. ; Returns the Video Page # currently displayed
  1868. ;
  1869. ; ENTRY: No Parameters are passed
  1870. ;
  1871. ; EXIT:  AX = Current Video Page being displayed
  1872. ;
  1873.  
  1874.     PUBLIC  GET_DISPLAY_PAGE
  1875.  
  1876. GET_DISPLAY_PAGE    PROC    FAR
  1877.  
  1878.     MOV     AX, DISPLAY_PAGE    ; Get Display Page #
  1879.     RET                         ; Exit & Clean Up Stack
  1880.  
  1881. GET_DISPLAY_PAGE    ENDP
  1882.  
  1883.  
  1884. ;=======================================
  1885. ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
  1886. ;=======================================
  1887. ;
  1888. ; Since a Logical Screen can be larger than the Physical
  1889. ; Screen, Scrolling is possible.  This routine sets the
  1890. ; Upper Left Corner of the Screen to the specified Pixel.
  1891. ; Also Sets the Display page to simplify combined page
  1892. ; flipping and scrolling.  When called this routine
  1893. ; syncronizes the display to the vertical blank.
  1894. ;
  1895. ; ENTRY: DisplayPage = Display Page to show on the screen
  1896. ;        Xpos        = # of pixels to shift screen right
  1897. ;        Ypos        = # of lines to shift screen down
  1898. ;
  1899. ; EXIT:  No meaningful values returned
  1900. ;
  1901.  
  1902. SW_STACK    STRUC
  1903.                 DW  ?   ; BP
  1904.                 DD  ?   ; Caller
  1905.     SW_Ypos     DW  ?   ; Y pos of UL Screen Corner
  1906.     SW_Xpos     DW  ?   ; X pos of UL Screen Corner
  1907.     SW_Page     DW  ?   ; (new) Display Page
  1908. SW_STACK    ENDS
  1909.  
  1910.         PUBLIC SET_WINDOW
  1911.  
  1912. SET_WINDOW  PROC    FAR
  1913.  
  1914.     PUSH    BP                  ; Preserve Registers
  1915.     MOV     BP, SP              ; Set up Stack Frame
  1916.  
  1917.     ; Check if our Scroll Offsets are Valid
  1918.  
  1919.     MOV     BX, [BP].SW_Page    ; Get Desired Page #
  1920.     CMP     BX, LAST_PAGE       ; Is Page # Valid?
  1921.     JAE     @SW_Exit            ; IF Not, Do Nothing
  1922.  
  1923.     MOV     AX, [BP].SW_Ypos    ; Get Desired Y Offset
  1924.     CMP     AX, MAX_YOFFSET     ; Is it Within Limits?
  1925.     JA      @SW_Exit            ; if not, exit
  1926.  
  1927.     MOV     CX, [BP].SW_Xpos    ; Get Desired X Offset
  1928.     CMP     CX, MAX_XOFFSET     ; Is it Within Limits?
  1929.     JA      @SW_Exit            ; if not, exit
  1930.  
  1931.     ; Compute proper Display start address to use
  1932.  
  1933.     MUL     SCREEN_WIDTH        ; AX = YOffset * Line Width
  1934.     SHR     CX, 2               ; CX / 4 = Bytes into Line
  1935.     ADD     AX, CX              ; AX = Offset of Upper Left Pixel
  1936.  
  1937.     MOV     CURRENT_MOFFSET, AX ; Save Offset Info
  1938.  
  1939.     MOV     DISPLAY_PAGE, BX    ; Set Current Page #
  1940.     SHL     BX, 1               ; Scale Page # to Word
  1941.     ADD     AX, PAGE_ADDR[BX]   ; Get offset in VGA to Page
  1942.     MOV     BX, AX              ; BX = Desired Display Start
  1943.  
  1944.     MOV     DX, INPUT_1         ; Input Status #1 Register
  1945.  
  1946.     ; Wait if we are currently in a Vertical Retrace
  1947.  
  1948. @SW_WAIT0:
  1949.     IN      AL, DX              ; Get VGA status
  1950.     AND     AL, VERT_RETRACE    ; In Display mode yet?
  1951.     JNZ     @SW_WAIT0           ; If Not, wait for it
  1952.  
  1953.     ; Set the Start Display Address to the new window
  1954.  
  1955.     MOV     DX, CRTC_Index      ; We Change the VGA Sequencer
  1956.     MOV     AL, START_DISP_LO   ; Display Start Low Register
  1957.     MOV     AH, BL              ; Low 8 Bits of Start Addr
  1958.     OUT     DX, AX              ; Set Display Addr Low
  1959.  
  1960.     MOV     AL, START_DISP_HI   ; Display Start High Register
  1961.     MOV     AH, BH              ; High 8 Bits of Start Addr
  1962.     OUT     DX, AX              ; Set Display Addr High
  1963.  
  1964.     ; Wait for a Vertical Retrace to smooth out things
  1965.  
  1966.     MOV     DX, INPUT_1         ; Input Status #1 Register
  1967.  
  1968. @SW_WAIT1:
  1969.     IN      AL, DX              ; Get VGA status
  1970.     AND     AL, VERT_RETRACE    ; Vertical Retrace Start?
  1971.     JZ      @SW_WAIT1           ; If Not, wait for it
  1972.  
  1973.     ; Now Set the Horizontal Pixel Pan values
  1974.  
  1975.     OUT_8   ATTRIB_Ctrl, PIXEL_PAN_REG  ; Select Pixel Pan Register
  1976.  
  1977.     MOV     AX, [BP].SW_Xpos    ; Get Desired X Offset
  1978.     AND     AL, 03              ; Get # of Pixels to Pan (0-3)
  1979.     SHL     AL, 1               ; Shift for 256 Color Mode
  1980.     OUT     DX, AL              ; Fine tune the display!
  1981.  
  1982. @SW_Exit:
  1983.     POP     BP                  ; Restore Saved Registers
  1984.     RET     6                   ; Exit and Clean up Stack
  1985.  
  1986. SET_WINDOW        ENDP
  1987.  
  1988.  
  1989. ;=============
  1990. ;GET_X_OFFSET%
  1991. ;=============
  1992. ;
  1993. ; Returns the X coordinate of the Pixel currently display
  1994. ; in the upper left corner of the display
  1995. ;
  1996. ; ENTRY: No Parameters are passed
  1997. ;
  1998. ; EXIT:  AX = Current Horizontal Scroll Offset
  1999. ;
  2000.  
  2001.     PUBLIC  GET_X_OFFSET
  2002.  
  2003. GET_X_OFFSET    PROC    FAR
  2004.  
  2005.     MOV     AX, CURRENT_XOFFSET ; Get current horz offset
  2006.     RET                         ; Exit & Clean Up Stack
  2007.  
  2008. GET_X_OFFSET    ENDP
  2009.  
  2010.  
  2011. ;=============
  2012. ;GET_Y_OFFSET%
  2013. ;=============
  2014. ;
  2015. ; Returns the Y coordinate of the Pixel currently display
  2016. ; in the upper left corner of the display
  2017. ;
  2018. ; ENTRY: No Parameters are passed
  2019. ;
  2020. ; EXIT:  AX = Current Vertical Scroll Offset
  2021. ;
  2022.  
  2023.     PUBLIC  GET_Y_OFFSET
  2024.  
  2025. GET_Y_OFFSET    PROC    FAR
  2026.  
  2027.     MOV     AX, CURRENT_YOFFSET ; Get current vertical offset
  2028.     RET                         ; Exit & Clean Up Stack
  2029.  
  2030. GET_Y_OFFSET    ENDP
  2031.  
  2032.  
  2033. ;============
  2034. ;SYNC_DISPLAY
  2035. ;============
  2036. ;
  2037. ; Pauses the computer until the next Vertical Retrace starts
  2038. ;
  2039. ; ENTRY: No Parameters are passed
  2040. ;
  2041. ; EXIT:  No meaningful values returned
  2042. ;
  2043.  
  2044.     PUBLIC  SYNC_DISPLAY
  2045.  
  2046. SYNC_DISPLAY    PROC    FAR
  2047.  
  2048.     MOV     DX, INPUT_1         ; Input Status #1 Register
  2049.  
  2050.     ; Wait for any current retrace to end
  2051.  
  2052. @SD_WAIT0:
  2053.     IN      AL, DX              ; Get VGA status
  2054.     AND     AL, VERT_RETRACE    ; In Display mode yet?
  2055.     JNZ     @SD_WAIT0           ; If Not, wait for it
  2056.  
  2057.     ; Wait for the start of the next vertical retrace
  2058.  
  2059. @SD_WAIT1:
  2060.     IN      AL, DX              ; Get VGA status
  2061.     AND     AL, VERT_RETRACE    ; Vertical Retrace Start?
  2062.     JZ      @SD_WAIT1           ; If Not, wait for it
  2063.  
  2064.     RET                         ; Exit & Clean Up Stack
  2065.  
  2066. SYNC_DISPLAY    ENDP
  2067.  
  2068.  
  2069.     ; ===== TEXT DISPLAY ROUTINES =====
  2070.  
  2071. ;==================================================
  2072. ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
  2073. ;==================================================
  2074. ;
  2075. ; Draws an ASCII Text Character using the currently selected
  2076. ; 8x8 font on the active display page.  It would be a simple
  2077. ; exercise to make this routine process variable height fonts.
  2078. ;
  2079. ; ENTRY: CharNum = ASCII character # to draw
  2080. ;        Xpos    = X position to draw Character at
  2081. ;        Ypos    = Y position of to draw Character at
  2082. ;        ColorF  = Color to draw text character in
  2083. ;        ColorB  = Color to set background to
  2084. ;
  2085. ; EXIT:  No meaningful values returned
  2086. ;
  2087.  
  2088. GPC_STACK   STRUC
  2089.     GPC_Width   DW  ?   ; Screen Width-1
  2090.     GPC_Lines   DB  ?,? ; Scan lines to Decode
  2091.     GPC_T_SETS  DW  ?   ; Saved Charset Segment
  2092.     GPC_T_SETO  DW  ?   ; Saved Charset Offset
  2093.                 DW  ?x4 ; DI, SI, DS, BP
  2094.                 DD  ?   ; Caller
  2095.     GPC_ColorB  DB  ?,? ; Background Color
  2096.     GPC_ColorF  DB  ?,? ; Text Color
  2097.     GPC_Ypos    DW  ?   ; Y Position to Print at
  2098.     GPC_Xpos    DW  ?   ; X position to Print at
  2099.     GPC_Char    DB  ?,? ; Character to Print
  2100. GPC_STACK   ENDS
  2101.  
  2102.         PUBLIC GPRINTC
  2103.  
  2104. GPRINTC     PROC    FAR
  2105.  
  2106.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2107.     SUB     SP, 8               ; Allocate WorkSpace on Stack
  2108.     MOV     BP, SP              ; Set up Stack Frame
  2109.  
  2110.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  2111.  
  2112.     MOV     AX, SCREEN_WIDTH    ; Get Logical Line Width
  2113.     MOV     BX, AX              ; BX = Screen Width
  2114.     DEC     BX                  ;    = Screen Width-1
  2115.     MOV     [BP].GPC_Width, BX  ; Save for later use
  2116.  
  2117.     MUL     [BP].GPC_Ypos       ; Start of Line = Ypos * Width
  2118.     ADD     DI, AX              ; DI -> Start of Line Ypos
  2119.  
  2120.     MOV     AX, [BP].GPC_Xpos   ; Get Xpos of Character
  2121.     MOV     CX, AX              ; Save Copy of Xpos
  2122.     SHR     AX, 2               ; Bytes into Line = Xpos/4
  2123.     ADD     DI, AX              ; DI -> (Xpos, Ypos)
  2124.  
  2125.     ;Get Source ADDR of Character Bit Map  & Save
  2126.  
  2127.     MOV     AL, [BP].GPC_Char   ; Get Character #
  2128.     TEST    AL, 080h            ; Is Hi Bit Set?
  2129.     JZ      @GPC_LowChar        ; Nope, use low char set ptr
  2130.  
  2131.     AND     AL, 07Fh            ; Mask Out Hi Bit
  2132.     MOV     BX, CHARSET_HI      ; BX = Char Set Ptr:Offset
  2133.     MOV     DX, CHARSET_HI+2    ; DX = Char Set Ptr:Segment
  2134.     JMP     s @GPC_Set_Char     ; Go Setup Character Ptr
  2135.  
  2136. @GPC_LowChar:
  2137.  
  2138.     MOV     BX, CHARSET_LOW     ; BX = Char Set Ptr:Offset
  2139.     MOV     DX, CHARSET_LOW+2   ; DX = Char Set Ptr:Segment
  2140.  
  2141. @GPC_Set_Char:
  2142.     MOV     [BP].GPC_T_SETS, DX ; Save Segment on Stack
  2143.  
  2144.     MOV     AH, 0               ; Valid #'s are 0..127
  2145.     SHL     AX, 3               ; * 8 Bytes Per Bitmap
  2146.     ADD     BX, AX              ; BX = Offset of Selected char
  2147.     MOV     [BP].GPC_T_SETO, BX ; Save Offset on Stack
  2148.  
  2149.     AND     CX, PLANE_BITS      ; Get Plane #
  2150.     MOV     CH, ALL_PLANES      ; Get Initial Plane mask
  2151.     SHL     CH, CL              ; And shift into position
  2152.     AND     CH, ALL_PLANES      ; And mask to lower nibble
  2153.  
  2154.     MOV     AL, 04              ; 4-Plane # = # of initial
  2155.     SUB     AL, CL              ; shifts to align bit mask
  2156.     MOV     CL, AL              ; Shift Count for SHL
  2157.  
  2158.     ;Get segment of character map
  2159.  
  2160.     OUT_8   SC_Index, MAP_MASK  ; Setup Plane selections
  2161.     INC     DX                  ; DX -> SC_Data
  2162.  
  2163.     MOV     AL, 08              ; 8 Lines to Process
  2164.     MOV     [BP].GPC_Lines, AL  ; Save on Stack
  2165.  
  2166.     MOV     DS, [BP].GPC_T_SETS ; Point to character set
  2167.  
  2168. @GPC_DECODE_CHAR_BYTE:
  2169.  
  2170.     MOV     SI, [BP].GPC_T_SETO ; Get DS:SI = String
  2171.  
  2172.     MOV     BH, [SI]            ; Get Bit Map
  2173.     INC     SI                  ; Point to Next Line
  2174.     MOV     [BP].GPC_T_SETO, SI ; And save new Pointer...
  2175.  
  2176.     CLR     AX                  ; Clear AX
  2177.  
  2178.     CLR     BL                      ; Clear BL
  2179.     ROL     BX, CL                  ; BL holds left edge bits
  2180.     MOV     SI, BX                  ; Use as Table Index
  2181.     AND     SI, CHAR_BITS           ; Get Low Bits
  2182.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2183.     JZ      @GPC_NO_LEFT1BITS       ; Skip if No Pixels to set
  2184.  
  2185.     MOV     AH, [BP].GPC_ColorF ; Get Foreground Color
  2186.     OUT     DX, AL              ; Set up Screen Mask
  2187.     MOV     ES:[DI], AH         ; Write Foreground color
  2188.  
  2189. @GPC_NO_LEFT1BITS:
  2190.     XOR     AL, CH              ; Invert mask for Background
  2191.     JZ      @GPC_NO_LEFT0BITS   ; Hey, no need for this
  2192.  
  2193.     MOV     AH, [BP].GPC_ColorB ; Get background Color
  2194.     OUT     DX, AL              ; Set up Screen Mask
  2195.     MOV     ES:[DI], AH         ; Write Foreground color
  2196.  
  2197.     ;Now Do Middle/Last Band
  2198.  
  2199. @GPC_NO_LEFT0BITS:
  2200.     INC     DI                  ; Point to next Byte
  2201.     ROL     BX, 4               ; Shift 4 bits
  2202.  
  2203.     MOV     SI, BX                  ; Make Lookup Pointer
  2204.     AND     SI, CHAR_BITS           ; Get Low Bits
  2205.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2206.     JZ      @GPC_NO_MIDDLE1BITS     ; Skip if no pixels to set
  2207.  
  2208.     MOV     AH, [BP].GPC_ColorF ; Get Foreground Color
  2209.     OUT     DX, AL              ; Set up Screen Mask
  2210.     MOV     ES:[DI], AH         ; Write Foreground color
  2211.  
  2212. @GPC_NO_MIDDLE1BITS:
  2213.     XOR     AL, ALL_PLANES      ; Invert mask for Background
  2214.     JZ      @GPC_NO_MIDDLE0BITS ; Hey, no need for this
  2215.  
  2216.     MOV     AH, [BP].GPC_ColorB ; Get background Color
  2217.     OUT     DX, AL              ; Set up Screen Mask
  2218.     MOV     ES:[DI], AH         ; Write Foreground color
  2219.  
  2220. @GPC_NO_MIDDLE0BITS:
  2221.     XOR     CH, ALL_PLANES      ; Invert Clip Mask
  2222.     CMP     CL, 4               ; Aligned by 4?
  2223.     JZ      @GPC_NEXT_LINE      ; If so, Exit now..
  2224.  
  2225.     INC     DI                  ; Point to next Byte
  2226.     ROL     BX, 4               ; Shift 4 bits
  2227.  
  2228.     MOV     SI, BX                  ; Make Lookup Pointer
  2229.     AND     SI, CHAR_BITS           ; Get Low Bits
  2230.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2231.     JZ      @GPC_NO_RIGHT1BITS      ; Skip if No Pixels to set
  2232.  
  2233.     MOV     AH, [BP].GPC_ColorF ; Get Foreground Color
  2234.     OUT     DX, AL              ; Set up Screen Mask
  2235.     MOV     ES:[DI], AH         ; Write Foreground color
  2236.  
  2237. @GPC_NO_RIGHT1BITS:
  2238.  
  2239.     XOR     AL, CH              ; Invert mask for Background
  2240.     JZ      @GPC_NO_RIGHT0BITS  ; Hey, no need for this
  2241.  
  2242.     MOV     AH, [BP].GPC_ColorB ; Get background Color
  2243.     OUT     DX, AL              ; Set up Screen Mask
  2244.     MOV     ES:[DI], AH         ; Write Foreground color
  2245.  
  2246. @GPC_NO_RIGHT0BITS:
  2247.     DEC     DI                  ; Adjust for Next Line Advance
  2248.  
  2249. @GPC_NEXT_LINE:
  2250.     ADD     DI, [BP].GPC_Width  ; Point to Next Line
  2251.     XOR     CH, CHAR_BITS       ; Flip the Clip mask back
  2252.  
  2253.     DEC     [BP].GPC_Lines      ; Count Down Lines
  2254.     JZ      @GPC_EXIT           ; Ok... Done!
  2255.  
  2256.     JMP     @GPC_DECODE_CHAR_BYTE   ; Again! Hey!
  2257.  
  2258. @GPC_EXIT:
  2259.     ADD     SP, 08              ; Deallocate stack workspace
  2260.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2261.     RET     10                  ; Exit and Clean up Stack
  2262.  
  2263. GPRINTC  ENDP
  2264.  
  2265.  
  2266. ;==========================================
  2267. ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
  2268. ;==========================================
  2269. ;
  2270. ; Transparently draws an ASCII Text Character using the
  2271. ; currently selected 8x8 font on the active display page.
  2272. ;
  2273. ; ENTRY: CharNum = ASCII character # to draw
  2274. ;        Xpos    = X position to draw Character at
  2275. ;        Ypos    = Y position of to draw Character at
  2276. ;        ColorF  = Color to draw text character in
  2277. ;
  2278. ; EXIT:  No meaningful values returned
  2279. ;
  2280.  
  2281. TGP_STACK   STRUC
  2282.     TGP_Width   DW  ?   ; Screen Width-1
  2283.     TGP_Lines   DB  ?,? ; Scan lines to Decode
  2284.     TGP_T_SETS  DW  ?   ; Saved Charset Segment
  2285.     TGP_T_SETO  DW  ?   ; Saved Charset Offset
  2286.                 DW  ?x4 ; DI, SI, DS, BP
  2287.                 DD  ?   ; Caller
  2288.     TGP_ColorF  DB  ?,? ; Text Color
  2289.     TGP_Ypos    DW  ?   ; Y Position to Print at
  2290.     TGP_Xpos    DW  ?   ; X position to Print at
  2291.     TGP_Char    DB  ?,? ; Character to Print
  2292. TGP_STACK   ENDS
  2293.  
  2294.         PUBLIC TGPRINTC
  2295.  
  2296. TGPRINTC    PROC    FAR
  2297.  
  2298.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2299.     SUB     SP, 8               ; Allocate WorkSpace on Stack
  2300.     MOV     BP, SP              ; Set up Stack Frame
  2301.  
  2302.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  2303.  
  2304.     MOV     AX, SCREEN_WIDTH    ; Get Logical Line Width
  2305.     MOV     BX, AX              ; BX = Screen Width
  2306.     DEC     BX                  ;    = Screen Width-1
  2307.     MOV     [BP].TGP_Width, BX  ; Save for later use
  2308.  
  2309.     MUL     [BP].TGP_Ypos       ; Start of Line = Ypos * Width
  2310.     ADD     DI, AX              ; DI -> Start of Line Ypos
  2311.  
  2312.     MOV     AX, [BP].TGP_Xpos   ; Get Xpos of Character
  2313.     MOV     CX, AX              ; Save Copy of Xpos
  2314.     SHR     AX, 2               ; Bytes into Line = Xpos/4
  2315.     ADD     DI, AX              ; DI -> (Xpos, Ypos)
  2316.  
  2317.     ;Get Source ADDR of Character Bit Map  & Save
  2318.  
  2319.     MOV     AL, [BP].TGP_Char   ; Get Character #
  2320.     TEST    AL, 080h            ; Is Hi Bit Set?
  2321.     JZ      @TGP_LowChar        ; Nope, use low char set ptr
  2322.  
  2323.     AND     AL, 07Fh            ; Mask Out Hi Bit
  2324.     MOV     BX, CHARSET_HI      ; BX = Char Set Ptr:Offset
  2325.     MOV     DX, CHARSET_HI+2    ; DX = Char Set Ptr:Segment
  2326.     JMP     s @TGP_Set_Char     ; Go Setup Character Ptr
  2327.  
  2328. @TGP_LowChar:
  2329.  
  2330.     MOV     BX, CHARSET_LOW     ; BX = Char Set Ptr:Offset
  2331.     MOV     DX, CHARSET_LOW+2   ; DX = Char Set Ptr:Segment
  2332.  
  2333. @TGP_Set_Char:
  2334.     MOV     [BP].TGP_T_SETS, DX ; Save Segment on Stack
  2335.  
  2336.     MOV     AH, 0               ; Valid #'s are 0..127
  2337.     SHL     AX, 3               ; * 8 Bytes Per Bitmap
  2338.     ADD     BX, AX              ; BX = Offset of Selected char
  2339.     MOV     [BP].TGP_T_SETO, BX ; Save Offset on Stack
  2340.  
  2341.     AND     CX, PLANE_BITS      ; Get Plane #
  2342.     MOV     CH, ALL_PLANES      ; Get Initial Plane mask
  2343.     SHL     CH, CL              ; And shift into position
  2344.     AND     CH, ALL_PLANES      ; And mask to lower nibble
  2345.  
  2346.     MOV     AL, 04              ; 4-Plane # = # of initial
  2347.     SUB     AL, CL              ; shifts to align bit mask
  2348.     MOV     CL, AL              ; Shift Count for SHL
  2349.  
  2350.     ;Get segment of character map
  2351.  
  2352.     OUT_8   SC_Index, MAP_MASK  ; Setup Plane selections
  2353.     INC     DX                  ; DX -> SC_Data
  2354.  
  2355.     MOV     AL, 08              ; 8 Lines to Process
  2356.     MOV     [BP].TGP_Lines, AL  ; Save on Stack
  2357.  
  2358.     MOV     DS, [BP].TGP_T_SETS ; Point to character set
  2359.  
  2360. @TGP_DECODE_CHAR_BYTE:
  2361.  
  2362.     MOV     SI, [BP].TGP_T_SETO ; Get DS:SI = String
  2363.  
  2364.     MOV     BH, [SI]            ; Get Bit Map
  2365.     INC     SI                  ; Point to Next Line
  2366.     MOV     [BP].TGP_T_SETO, SI ; And save new Pointer...
  2367.  
  2368.     MOV     AH, [BP].TGP_ColorF ; Get Foreground Color
  2369.  
  2370.     CLR     BL                      ; Clear BL
  2371.     ROL     BX, CL                  ; BL holds left edge bits
  2372.     MOV     SI, BX                  ; Use as Table Index
  2373.     AND     SI, CHAR_BITS           ; Get Low Bits
  2374.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2375.     JZ      @TGP_NO_LEFT1BITS       ; Skip if No Pixels to set
  2376.  
  2377.     OUT     DX, AL              ; Set up Screen Mask
  2378.     MOV     ES:[DI], AH         ; Write Foreground color
  2379.  
  2380.     ;Now Do Middle/Last Band
  2381.  
  2382. @TGP_NO_LEFT1BITS:
  2383.  
  2384.     INC     DI                  ; Point to next Byte
  2385.     ROL     BX, 4               ; Shift 4 bits
  2386.  
  2387.     MOV     SI, BX                  ; Make Lookup Pointer
  2388.     AND     SI, CHAR_BITS           ; Get Low Bits
  2389.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2390.     JZ      @TGP_NO_MIDDLE1BITS     ; Skip if no pixels to set
  2391.  
  2392.     OUT     DX, AL              ; Set up Screen Mask
  2393.     MOV     ES:[DI], AH         ; Write Foreground color
  2394.  
  2395. @TGP_NO_MIDDLE1BITS:
  2396.     XOR     CH, ALL_PLANES      ; Invert Clip Mask
  2397.     CMP     CL, 4               ; Aligned by 4?
  2398.     JZ      @TGP_NEXT_LINE      ; If so, Exit now..
  2399.  
  2400.     INC     DI                  ; Point to next Byte
  2401.     ROL     BX, 4               ; Shift 4 bits
  2402.  
  2403.     MOV     SI, BX                  ; Make Lookup Pointer
  2404.     AND     SI, CHAR_BITS           ; Get Low Bits
  2405.     MOV     AL, Char_Plane_Data[SI] ; Get Mask in AL
  2406.     JZ      @TGP_NO_RIGHT1BITS      ; Skip if No Pixels to set
  2407.  
  2408.     OUT     DX, AL              ; Set up Screen Mask
  2409.     MOV     ES:[DI], AH         ; Write Foreground color
  2410.  
  2411. @TGP_NO_RIGHT1BITS:
  2412.  
  2413.     DEC     DI                  ; Adjust for Next Line Advance
  2414.  
  2415. @TGP_NEXT_LINE:
  2416.     ADD     DI, [BP].TGP_Width  ; Point to Next Line
  2417.     XOR     CH, CHAR_BITS       ; Flip the Clip mask back
  2418.  
  2419.     DEC     [BP].TGP_Lines      ; Count Down Lines
  2420.     JZ      @TGP_EXIT           ; Ok... Done!
  2421.  
  2422.     JMP     @TGP_DECODE_CHAR_BYTE   ; Again! Hey!
  2423.  
  2424. @TGP_EXIT:
  2425.     ADD     SP, 08              ; Deallocate stack workspace
  2426.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2427.     RET     8                   ; Exit and Clean up Stack
  2428.  
  2429. TGPRINTC    ENDP
  2430.  
  2431.  
  2432. ;===============================================================
  2433. ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
  2434. ;===============================================================
  2435. ;
  2436. ; Routine to quickly Print a null terminated ASCII string on the
  2437. ; active display page up to a maximum length.
  2438. ;
  2439. ; ENTRY: String  = Far Pointer to ASCII string to print
  2440. ;        MaxLen  = # of characters to print if no null found
  2441. ;        Xpos    = X position to draw Text at
  2442. ;        Ypos    = Y position of to draw Text at
  2443. ;        ColorF  = Color to draw text in
  2444. ;        ColorB  = Color to set background to
  2445. ;
  2446. ; EXIT:  No meaningful values returned
  2447. ;
  2448.  
  2449. PS_STACK    STRUC
  2450.                 DW  ?x4 ; DI, SI, DS, BP
  2451.                 DD  ?   ; Caller
  2452.     PS_ColorB   DW  ?   ; Background Color
  2453.     PS_ColorF   DW  ?   ; Text Color
  2454.     PS_Ypos     DW  ?   ; Y Position to Print at
  2455.     PS_Xpos     DW  ?   ; X position to Print at
  2456.     PS_Len      DW  ?   ; Maximum Length of string to print
  2457.     PS_Text     DW  ?,? ; Far Ptr to Text String
  2458. PS_STACK    ENDS
  2459.  
  2460.         PUBLIC  PRINT_STR
  2461.  
  2462. PRINT_STR   PROC    FAR
  2463.  
  2464.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2465.     MOV     BP, SP              ; Set up Stack Frame
  2466.  
  2467. @PS_Print_It:
  2468.  
  2469.     MOV     CX, [BP].PS_Len     ; Get Remaining text Length
  2470.     JCXZ    @PS_Exit            ; Exit when out of text
  2471.  
  2472.     LES     DI, d [BP].PS_Text  ; ES:DI -> Current Char in Text
  2473.     MOV     AL, ES:[DI]         ; AL = Text Character
  2474.     AND     AX, 00FFh           ; Clear High Word
  2475.     JZ      @PS_Exit            ; Exit if null character
  2476.  
  2477.     DEC     [BP].PS_Len         ; Remaining Text length--
  2478.     INC     [BP].PS_Text        ; Point to Next text char
  2479.  
  2480.     ; Set up Call to GPRINTC
  2481.  
  2482.     PUSH    AX                  ; Set Character Parameter
  2483.     MOV     BX, [BP].PS_Xpos    ; Get Xpos
  2484.     PUSH    BX                  ; Set Xpos Parameter
  2485.     ADD     BX, 8               ; Advance 1 Char to Right
  2486.     MOV     [BP].PS_Xpos, BX    ; Save for next time through
  2487.  
  2488.     MOV     BX, [BP].PS_Ypos    ; Get Ypos
  2489.     PUSH    BX                  ; Set Ypos Parameter
  2490.  
  2491.     MOV     BX, [BP].PS_ColorF  ; Get Text Color
  2492.     PUSH    BX                  ; Set ColorF Parameter
  2493.  
  2494.     MOV     BX, [BP].PS_ColorB  ; Get Background Color
  2495.     PUSH    BX                  ; Set ColorB Parameter
  2496.  
  2497.     CALL    f GPRINTC           ; Print Character!
  2498.     JMP     s @PS_Print_It      ; Process next character
  2499.  
  2500. @PS_Exit:
  2501.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2502.     RET     14                  ; Exit and Clean up Stack
  2503.  
  2504. PRINT_STR  ENDP
  2505.  
  2506.  
  2507. ;================================================================
  2508. ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
  2509. ;================================================================
  2510. ;
  2511. ; Routine to quickly transparently Print a null terminated ASCII
  2512. ; string on the active display page up to a maximum length.
  2513. ;
  2514. ; ENTRY: String  = Far Pointer to ASCII string to print
  2515. ;        MaxLen  = # of characters to print if no null found
  2516. ;        Xpos    = X position to draw Text at
  2517. ;        Ypos    = Y position of to draw Text at
  2518. ;        ColorF  = Color to draw text in
  2519. ;
  2520. ; EXIT:  No meaningful values returned
  2521. ;
  2522.  
  2523. TPS_STACK   STRUC
  2524.                 DW  ?x4 ; DI, SI, DS, BP
  2525.                 DD  ?   ; Caller
  2526.     TPS_ColorF  DW  ?   ; Text Color
  2527.     TPS_Ypos    DW  ?   ; Y Position to Print at
  2528.     TPS_Xpos    DW  ?   ; X position to Print at
  2529.     TPS_Len     DW  ?   ; Maximum Length of string to print
  2530.     TPS_Text    DW  ?,? ; Far Ptr to Text String
  2531. TPS_STACK   ENDS
  2532.  
  2533.         PUBLIC  TPRINT_STR
  2534.  
  2535. TPRINT_STR  PROC    FAR
  2536.  
  2537.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2538.     MOV     BP, SP              ; Set up Stack Frame
  2539.  
  2540. @TPS_Print_It:
  2541.  
  2542.     MOV     CX, [BP].TPS_Len    ; Get Remaining text Length
  2543.     JCXZ    @TPS_Exit           ; Exit when out of text
  2544.  
  2545.     LES     DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text
  2546.     MOV     AL, ES:[DI]         ; AL = Text Character
  2547.     AND     AX, 00FFh           ; Clear High Word
  2548.     JZ      @TPS_Exit           ; Exit if null character
  2549.  
  2550.     DEC     [BP].TPS_Len        ; Remaining Text length--
  2551.     INC     [BP].TPS_Text       ; Point to Next text char
  2552.  
  2553.     ; Set up Call to TGPRINTC
  2554.  
  2555.     PUSH    AX                  ; Set Character Parameter
  2556.     MOV     BX, [BP].TPS_Xpos   ; Get Xpos
  2557.     PUSH    BX                  ; Set Xpos Parameter
  2558.     ADD     BX, 8               ; Advance 1 Char to Right
  2559.     MOV     [BP].TPS_Xpos, BX   ; Save for next time through
  2560.  
  2561.     MOV     BX, [BP].TPS_Ypos   ; Get Ypos
  2562.     PUSH    BX                  ; Set Ypos Parameter
  2563.  
  2564.     MOV     BX, [BP].TPS_ColorF ; Get Text Color
  2565.     PUSH    BX                  ; Set ColorF Parameter
  2566.  
  2567.     CALL    f TGPRINTC          ; Print Character!
  2568.     JMP     s @TPS_Print_It     ; Process next character
  2569.  
  2570. @TPS_Exit:
  2571.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2572.     RET     12                  ; Exit and Clean up Stack
  2573.  
  2574. TPRINT_STR  ENDP
  2575.  
  2576.  
  2577. ;===========================================
  2578. ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
  2579. ;===========================================
  2580. ;
  2581. ; Allows the user to specify their own font data for
  2582. ; wither the lower or upper 128 characters.
  2583. ;
  2584. ; ENTRY: FontData   = Far Pointer to Font Bitmaps
  2585. ;        FontNumber = Which half of set this is
  2586. ;                   = 0, Lower 128 characters
  2587. ;                   = 1, Upper 128 characters
  2588. ;
  2589. ; EXIT:  No meaningful values returned
  2590. ;
  2591.  
  2592. SDF_STACK   STRUC
  2593.                 DW  ?   ; BP
  2594.                 DD  ?   ; Caller
  2595.     SDF_Which   DW  ?   ; Hi Table/Low Table Flag
  2596.     SDF_Font    DD  ?   ; Far Ptr to Font Table
  2597. SDF_STACK   ENDS
  2598.  
  2599.     PUBLIC  SET_DISPLAY_FONT
  2600.  
  2601. SET_DISPLAY_FONT    PROC    FAR
  2602.  
  2603.     PUSH    BP                  ; Preserve Registers
  2604.     MOV     BP, SP              ; Set up Stack Frame
  2605.  
  2606.     LES     DI, [BP].SDF_Font   ; Get Far Ptr to Font
  2607.  
  2608.     MOV     SI, o CHARSET_LOW   ; Assume Lower 128 chars
  2609.     TEST    [BP].SDF_Which, 1   ; Font #1 selected?
  2610.     JZ      @SDF_Set_Font       ; If not, skip ahead
  2611.  
  2612.     MOV     SI, o CHARSET_HI    ; Ah, really it's 128-255
  2613.  
  2614. @SDF_Set_Font:
  2615.     MOV     [SI], DI            ; Set Font Pointer Offset
  2616.     MOV     [SI+2], ES          ; Set Font Pointer Segment
  2617.  
  2618.     POP     BP                  ; Restore Registers
  2619.     RET     6                   ; We are Done.. Outa here
  2620.  
  2621. SET_DISPLAY_FONT    ENDP
  2622.  
  2623.  
  2624.     ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
  2625.  
  2626. ;======================================================
  2627. ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
  2628. ;======================================================
  2629. ;
  2630. ; Draws a variable sized Graphics Bitmap such as a
  2631. ; picture or an Icon on the current Display Page in
  2632. ; Mode X.  The Bitmap is stored in a linear byte array
  2633. ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
  2634. ; This is the same linear manner as mode 13h graphics.
  2635. ;
  2636. ; ENTRY: Image  = Far Pointer to Bitmap Data
  2637. ;        Xpos   = X position to Place Upper Left pixel at
  2638. ;        Ypos   = Y position to Place Upper Left pixel at
  2639. ;        Width  = Width of the Bitmap in Pixels
  2640. ;        Height = Height of the Bitmap in Pixels
  2641. ;
  2642. ; EXIT:  No meaningful values returned
  2643. ;
  2644.  
  2645. DB_STACK    STRUC
  2646.     DB_LineO    DW  ?   ; Offset to Next Line
  2647.     DB_PixCount DW  ?   ; (Minimum) # of Pixels/Line
  2648.     DB_Start    DW  ?   ; Addr of Upper Left Pixel
  2649.     DB_PixSkew  DW  ?   ; # of bytes to Adjust EOL
  2650.     DB_SkewFlag DW  ?   ; Extra Pix on Plane Flag
  2651.                 DW  ?x4 ; DI, SI, DS, BP
  2652.                 DD  ?   ; Caller
  2653.     DB_Height   DW  ?   ; Height of Bitmap in Pixels
  2654.     DB_Width    DW  ?   ; Width of Bitmap in Pixels
  2655.     DB_Ypos     DW  ?   ; Y position to Draw Bitmap at
  2656.     DB_Xpos     DW  ?   ; X position to Draw Bitmap at
  2657.     DB_Image    DD  ?   ; Far Pointer to Graphics Bitmap
  2658. DB_STACK    ENDS
  2659.  
  2660.         PUBLIC    DRAW_BITMAP
  2661.  
  2662. DRAW_BITMAP PROC    FAR
  2663.  
  2664.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2665.     SUB     SP, 10              ; Allocate workspace
  2666.     MOV     BP, SP              ; Set up Stack Frame
  2667.  
  2668.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  2669.     CLD                         ; Direction Flag = Forward
  2670.  
  2671.     MOV     AX, [BP].DB_Ypos    ; Get UL Corner Ypos
  2672.     MUL     SCREEN_WIDTH        ; AX = Offset to Line Ypos
  2673.  
  2674.     MOV     BX, [BP].DB_Xpos    ; Get UL Corner Xpos
  2675.     MOV     CL, BL              ; Save Plane # in CL
  2676.     SHR     BX, 2               ; Xpos/4 = Offset Into Line
  2677.  
  2678.     ADD     DI, AX              ; ES:DI -> Start of Line
  2679.     ADD     DI, BX              ; ES:DI -> Upper Left Pixel
  2680.     MOV     [BP].DB_Start, DI   ; Save Starting Addr
  2681.  
  2682.     ; Compute line to line offset
  2683.  
  2684.     MOV     BX, [BP].DB_Width   ; Get Width of Image
  2685.     MOV     DX, BX              ; Save Copy in DX
  2686.     SHR     BX, 2               ; /4 = width in bands
  2687.     MOV     AX, SCREEN_WIDTH    ; Get Screen Width
  2688.     SUB     AX, BX              ; - (Bitmap Width/4)
  2689.  
  2690.     MOV     [BP].DB_LineO, AX       ; Save Line Width offset
  2691.     MOV     [BP].DB_PixCount, BX    ; Minimum # pix to copy
  2692.  
  2693.     AND     DX, PLANE_BITS          ; Get "partial band" size (0-3)
  2694.     MOV     [BP].DB_PixSkew, DX     ; Also End of Line Skew
  2695.     MOV     [BP].DB_SkewFlag, DX    ; Save as Flag/Count
  2696.  
  2697.     AND     CX, PLANE_BITS      ; CL = Starting Plane #
  2698.     MOV     AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
  2699.     SHL     AH, CL              ; Select correct Plane
  2700.     OUT_16  SC_Index, AX        ; Select Plane...
  2701.     MOV     BH, AH              ; BH = Saved Plane Mask
  2702.     MOV     BL, 4               ; BL = Planes to Copy
  2703.  
  2704. @DB_COPY_PLANE:
  2705.  
  2706.     LDS     SI, [BP].DB_Image   ; DS:SI-> Source Image
  2707.     MOV     DX, [BP].DB_Height  ; # of Lines to Copy
  2708.     MOV     DI, [BP].DB_Start   ; ES:DI-> Dest pos
  2709.  
  2710. @DB_COPY_LINE:
  2711.     MOV     CX, [BP].DB_PixCount    ; Min # to copy
  2712.  
  2713.     TEST    CL, 0FCh            ; 16+PixWide?
  2714.     JZ      @DB_COPY_REMAINDER  ; Nope...
  2715.  
  2716.     ; Pixel Copy loop has been unrolled to x4
  2717.  
  2718. @DB_COPY_LOOP:
  2719.     MOVSB                       ; Copy Bitmap Pixel
  2720.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2721.     MOVSB                       ; Copy Bitmap Pixel
  2722.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2723.     MOVSB                       ; Copy Bitmap Pixel
  2724.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2725.     MOVSB                       ; Copy Bitmap Pixel
  2726.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2727.  
  2728.     SUB     CL, 4               ; Pixels to Copy=-4
  2729.     TEST    CL, 0FCh            ; 4+ Pixels Left?
  2730.     JNZ     @DB_COPY_LOOP       ; if so, do another block
  2731.  
  2732. @DB_COPY_REMAINDER:
  2733.     JCXZ    @DB_NEXT_LINE       ; Any Pixels left on line
  2734.  
  2735. @DB_COPY2:
  2736.     MOVSB                       ; Copy Bitmap Pixel
  2737.     ADD     SI,3                ; Skip to Next Byte in same plane
  2738.     LOOPx   CX, @DB_COPY2       ; Pixels to Copy--, Loop until done
  2739.  
  2740. @DB_NEXT_LINE:
  2741.  
  2742.     ; any Partial Pixels? (some planes only)
  2743.  
  2744.     OR      CX, [BP].DB_SkewFlag    ; Get Skew Count
  2745.     JZ      @DB_NEXT2               ; if no partial pixels
  2746.  
  2747.     MOVSB                       ; Copy Bitmap Pixel
  2748.     DEC     DI                  ; Back up to align
  2749.     DEC     SI                  ; Back up to align
  2750.  
  2751. @DB_NEXT2:
  2752.     ADD     SI, [BP].DB_PixSkew ; Adjust Skew
  2753.     ADD     DI, [BP].DB_LineO   ; Set to Next Display Line
  2754.     LOOPx   DX, @DB_COPY_LINE   ; Lines to Copy--, Loop if more
  2755.  
  2756.     ; Copy Next Plane....
  2757.  
  2758.     DEC     BL                  ; Planes to Go--
  2759.     JZ      @DB_Exit            ; Hey! We are done
  2760.  
  2761.     ROL     BH, 1               ; Next Plane in line...
  2762.     OUT_8   SC_Data, BH         ; Select Plane
  2763.  
  2764.     CMP     AL, 12h             ; Carry Set if AL=11h
  2765.     ADC     [BP].DB_Start, 0    ; Screen Addr =+Carry
  2766.     INC     w [BP].DB_Image     ; Start @ Next Byte
  2767.  
  2768.     SUB     [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew
  2769.     ADC     [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
  2770.  
  2771.     JMP     s @DB_COPY_PLANE    ; Go Copy the Next Plane
  2772.  
  2773. @DB_Exit:
  2774.     ADD     SP, 10              ; Deallocate workspace
  2775.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2776.     RET     12                  ; Exit and Clean up Stack
  2777.  
  2778. DRAW_BITMAP   ENDP
  2779.  
  2780.  
  2781. ;=======================================================
  2782. ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
  2783. ;=======================================================
  2784. ;
  2785. ; Transparently Draws a variable sized Graphics Bitmap
  2786. ; such as a picture or an Icon on the current Display Page
  2787. ; in Mode X.  Pixels with a value of 0 are not drawn,
  2788. ; leaving the previous "background" contents intact.
  2789. ;
  2790. ; The Bitmap format is the same as for the DRAW_BITMAP function.
  2791. ;
  2792. ; ENTRY: Image  = Far Pointer to Bitmap Data
  2793. ;        Xpos   = X position to Place Upper Left pixel at
  2794. ;        Ypos   = Y position to Place Upper Left pixel at
  2795. ;        Width  = Width of the Bitmap in Pixels
  2796. ;        Height = Height of the Bitmap in Pixels
  2797. ;
  2798. ; EXIT:  No meaningful values returned
  2799. ;
  2800.  
  2801. TB_STACK    STRUC
  2802.     TB_LineO    DW  ?   ; Offset to Next Line
  2803.     TB_PixCount DW  ?   ; (Minimum) # of Pixels/Line
  2804.     TB_Start    DW  ?   ; Addr of Upper Left Pixel
  2805.     TB_PixSkew  DW  ?   ; # of bytes to Adjust EOL
  2806.     TB_SkewFlag DW  ?   ; Extra Pix on Plane Flag
  2807.                 DW  ?x4 ; DI, SI, DS, BP
  2808.                 DD  ?   ; Caller
  2809.     TB_Height   DW  ?   ; Height of Bitmap in Pixels
  2810.     TB_Width    DW  ?   ; Width of Bitmap in Pixels
  2811.     TB_Ypos     DW  ?   ; Y position to Draw Bitmap at
  2812.     TB_Xpos     DW  ?   ; X position to Draw Bitmap at
  2813.     TB_Image    DD  ?   ; Far Pointer to Graphics Bitmap
  2814. TB_STACK    ENDS
  2815.  
  2816.         PUBLIC    TDRAW_BITMAP
  2817.  
  2818. TDRAW_BITMAP    PROC    FAR
  2819.  
  2820.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2821.     SUB     SP, 10              ; Allocate workspace
  2822.     MOV     BP, SP              ; Set up Stack Frame
  2823.  
  2824.     LES     DI, d CURRENT_PAGE  ; Point to Active VGA Page
  2825.     CLD                         ; Direction Flag = Forward
  2826.  
  2827.     MOV     AX, [BP].TB_Ypos    ; Get UL Corner Ypos
  2828.     MUL     SCREEN_WIDTH        ; AX = Offset to Line Ypos
  2829.  
  2830.     MOV     BX, [BP].TB_Xpos    ; Get UL Corner Xpos
  2831.     MOV     CL, BL              ; Save Plane # in CL
  2832.     SHR     BX, 2               ; Xpos/4 = Offset Into Line
  2833.  
  2834.     ADD     DI, AX              ; ES:DI -> Start of Line
  2835.     ADD     DI, BX              ; ES:DI -> Upper Left Pixel
  2836.     MOV     [BP].TB_Start, DI   ; Save Starting Addr
  2837.  
  2838.     ; Compute line to line offset
  2839.  
  2840.     MOV     BX, [BP].TB_Width   ; Get Width of Image
  2841.     MOV     DX, BX              ; Save Copy in DX
  2842.     SHR     BX, 2               ; /4 = width in bands
  2843.     MOV     AX, SCREEN_WIDTH    ; Get Screen Width
  2844.     SUB     AX, BX              ; - (Bitmap Width/4)
  2845.  
  2846.     MOV     [BP].TB_LineO, AX       ; Save Line Width offset
  2847.     MOV     [BP].TB_PixCount, BX    ; Minimum # pix to copy
  2848.  
  2849.     AND     DX, PLANE_BITS          ; Get "partial band" size (0-3)
  2850.     MOV     [BP].TB_PixSkew, DX     ; Also End of Line Skew
  2851.     MOV     [BP].TB_SkewFlag, DX    ; Save as Flag/Count
  2852.  
  2853.     AND     CX, PLANE_BITS      ; CL = Starting Plane #
  2854.     MOV     AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
  2855.     SHL     AH, CL              ; Select correct Plane
  2856.     OUT_16  SC_Index, AX        ; Select Plane...
  2857.     MOV     BH, AH              ; BH = Saved Plane Mask
  2858.     MOV     BL, 4               ; BL = Planes to Copy
  2859.  
  2860. @TB_COPY_PLANE:
  2861.  
  2862.     LDS     SI, [BP].TB_Image   ; DS:SI-> Source Image
  2863.     MOV     DX, [BP].TB_Height  ; # of Lines to Copy
  2864.     MOV     DI, [BP].TB_Start   ; ES:DI-> Dest pos
  2865.  
  2866.     ; Here AH is set with the value to be considered
  2867.     ; "Transparent".  It can be changed!
  2868.  
  2869.     MOV     AH, 0               ; Value to Detect 0
  2870.  
  2871. @TB_COPY_LINE:
  2872.     MOV     CX, [BP].TB_PixCount    ; Min # to copy
  2873.  
  2874.     TEST    CL, 0FCh            ; 16+PixWide?
  2875.     JZ      @TB_COPY_REMAINDER  ; Nope...
  2876.  
  2877.     ; Pixel Copy loop has been unrolled to x4
  2878.  
  2879. @TB_COPY_LOOP:
  2880.     LODSB                       ; Get Pixel Value in AL
  2881.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2882.     CMP     AL, AH              ; It is "Transparent"?
  2883.     JE      @TB_SKIP_01         ; Skip ahead if so
  2884.     MOV     ES:[DI], AL         ; Copy Pixel to VGA screen
  2885.  
  2886. @TB_SKIP_01:
  2887.     LODSB                       ; Get Pixel Value in AL
  2888.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2889.     CMP     AL, AH              ; It is "Transparent"?
  2890.     JE      @TB_SKIP_02         ; Skip ahead if so
  2891.     MOV     ES:[DI+1], AL       ; Copy Pixel to VGA screen
  2892.  
  2893. @TB_SKIP_02:
  2894.     LODSB                       ; Get Pixel Value in AL
  2895.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2896.     CMP     AL, AH              ; It is "Transparent"?
  2897.     JE      @TB_SKIP_03         ; Skip ahead if so
  2898.     MOV     ES:[DI+2], AL       ; Copy Pixel to VGA screen
  2899.  
  2900. @TB_SKIP_03:
  2901.     LODSB                       ; Get Pixel Value in AL
  2902.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2903.     CMP     AL, AH              ; It is "Transparent"?
  2904.     JE      @TB_SKIP_04         ; Skip ahead if so
  2905.     MOV     ES:[DI+3], AL       ; Copy Pixel to VGA screen
  2906.  
  2907. @TB_SKIP_04:
  2908.     ADD     DI, 4               ; Adjust Pixel Write Location
  2909.     SUB     CL, 4               ; Pixels to Copy=-4
  2910.     TEST    CL, 0FCh            ; 4+ Pixels Left?
  2911.     JNZ     @TB_COPY_LOOP       ; if so, do another block
  2912.  
  2913. @TB_COPY_REMAINDER:
  2914.     JCXZ    @TB_NEXT_LINE       ; Any Pixels left on line
  2915.  
  2916. @TB_COPY2:
  2917.     LODSB                       ; Get Pixel Value in AL
  2918.     ADD     SI, 3               ; Skip to Next Byte in same plane
  2919.     CMP     AL, AH              ; It is "Transparent"?
  2920.     JE      @TB_SKIP_05         ; Skip ahead if so
  2921.     MOV     ES:[DI], AL         ; Copy Pixel to VGA screen
  2922.  
  2923. @TB_SKIP_05:
  2924.     INC     DI                  ; Advance Dest Addr
  2925.     LOOPx   CX, @TB_COPY2       ; Pixels to Copy--, Loop until done
  2926.  
  2927. @TB_NEXT_LINE:
  2928.  
  2929.     ; any Partial Pixels? (some planes only)
  2930.  
  2931.     OR      CX, [BP].TB_SkewFlag    ; Get Skew Count
  2932.     JZ      @TB_NEXT2               ; if no partial pixels
  2933.  
  2934.     LODSB                       ; Get Pixel Value in AL
  2935.     DEC     SI                  ; Backup to Align
  2936.     CMP     AL, AH              ; It is "Transparent"?
  2937.     JE      @TB_NEXT2           ; Skip ahead if so
  2938.     MOV     ES:[DI], AL         ; Copy Pixel to VGA screen
  2939.  
  2940. @TB_NEXT2:
  2941.     ADD     SI, [BP].TB_PixSkew ; Adjust Skew
  2942.     ADD     DI, [BP].TB_LineO   ; Set to Next Display Line
  2943.     LOOPx   DX, @TB_COPY_LINE   ; Lines to Copy--, Loop if More
  2944.  
  2945.     ;Copy Next Plane....
  2946.  
  2947.     DEC     BL                  ; Planes to Go--
  2948.     JZ      @TB_Exit            ; Hey! We are done
  2949.  
  2950.     ROL     BH, 1               ; Next Plane in line...
  2951.     OUT_8   SC_Data, BH         ; Select Plane
  2952.  
  2953.     CMP     AL, 12h             ; Carry Set if AL=11h
  2954.     ADC     [BP].TB_Start, 0    ; Screen Addr =+Carry
  2955.     INC     w [BP].TB_Image     ; Start @ Next Byte
  2956.  
  2957.     SUB     [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew
  2958.     ADC     [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
  2959.  
  2960.     JMP     @TB_COPY_PLANE      ; Go Copy the next Plane
  2961.  
  2962. @TB_Exit:
  2963.     ADD     SP, 10              ; Deallocate workspace
  2964.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  2965.     RET     12                  ; Exit and Clean up Stack
  2966.  
  2967. TDRAW_BITMAP    ENDP
  2968.  
  2969.  
  2970.     ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
  2971.  
  2972. ;==================================
  2973. ;COPY_PAGE (SourcePage%, DestPage%)
  2974. ;==================================
  2975. ;
  2976. ; Duplicate on display page onto another
  2977. ;
  2978. ; ENTRY: SourcePage = Display Page # to Duplicate
  2979. ;        DestPage   = Display Page # to hold copy
  2980. ;
  2981. ; EXIT:  No meaningful values returned
  2982. ;
  2983.  
  2984. CP_STACK    STRUC
  2985.                 DW  ?x4 ; DI, SI, DS, BP
  2986.                 DD  ?   ; Caller
  2987.     CP_DestP    DW  ?   ; Page to hold copied image
  2988.     CP_SourceP  DW  ?   ; Page to Make copy from
  2989. CP_STACK    ENDS
  2990.  
  2991.         PUBLIC    COPY_PAGE
  2992.  
  2993. COPY_PAGE   PROC    FAR
  2994.  
  2995.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  2996.     MOV     BP, SP              ; Set up Stack Frame
  2997.     CLD                         ; Block Xfer Forwards
  2998.  
  2999.     ; Make sure Page #'s are valid
  3000.  
  3001.     MOV     AX, [BP].CP_SourceP ; Get Source Page #
  3002.     CMP     AX, LAST_PAGE       ; is it > Max Page #?
  3003.     JAE     @CP_Exit            ; if so, abort
  3004.  
  3005.     MOV     BX, [BP].CP_DestP   ; Get Destination Page #
  3006.     CMP     BX, LAST_PAGE       ; is it > Max Page #?
  3007.     JAE     @CP_Exit            ; if so, abort
  3008.  
  3009.     CMP     AX, BX              ; Pages #'s the same?
  3010.     JE      @CP_Exit            ; if so, abort
  3011.  
  3012.     ; Setup DS:SI and ES:DI to Video Pages
  3013.  
  3014.     SHL     BX, 1               ; Scale index to Word
  3015.     MOV     DI, PAGE_ADDR[BX]   ; Offset to Dest Page
  3016.  
  3017.     MOV     BX, AX              ; Index to Source page
  3018.     SHL     BX, 1               ; Scale index to Word
  3019.     MOV     SI, PAGE_ADDR[BX]   ; Offset to Source Page
  3020.  
  3021.     MOV     CX, PAGE_SIZE       ; Get size of Page
  3022.     MOV     AX, CURRENT_SEGMENT ; Get Video Mem Segment
  3023.     MOV     ES, AX              ; ES:DI -> Dest Page
  3024.     MOV     DS, AX              ; DS:SI -> Source Page
  3025.  
  3026.     ; Setup VGA registers for Mem to Mem copy
  3027.  
  3028.     OUT_16  GC_Index, LATCHES_ON    ; Data from Latches = on
  3029.     OUT_16  SC_Index, ALL_PLANES_ON ; Copy all Planes
  3030.  
  3031.     ; Note.. Do *NOT* use MOVSW or MOVSD - they will
  3032.     ; Screw with the latches which are 8 bits x 4
  3033.  
  3034.     REP     MOVSB               ; Copy entire Page!
  3035.  
  3036.     ; Reset VGA for normal memory access
  3037.  
  3038.     OUT_16  GC_Index, LATCHES_OFF   ; Data from Latches = off
  3039.  
  3040. @CP_Exit:
  3041.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  3042.     RET     4                   ; Exit and Clean up Stack
  3043.  
  3044. COPY_PAGE   ENDP
  3045.  
  3046.  
  3047. ;==========================================================================
  3048. ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
  3049. ;==========================================================================
  3050. ;
  3051. ; Copies a Bitmap Image from one Display Page to Another
  3052. ; This Routine is Limited to copying Images with the same
  3053. ; Plane Alignment.  To Work: (X1 MOD 4) must = (DestX1 MOD 4)
  3054. ; Copying an Image to the Same Page is supported, but results
  3055. ; may be defined when the when the rectangular areas
  3056. ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -
  3057. ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
  3058. ; No Paramter checking to done to insure that
  3059. ; X2 >= X1 and Y2 >= Y1.  Be Careful...
  3060. ;
  3061. ; ENTRY: SourcePage = Display Page # with Source Image
  3062. ;        X1         = Upper Left Xpos of Source Image
  3063. ;        Y1         = Upper Left Ypos of Source Image
  3064. ;        X2         = Lower Right Xpos of Source Image
  3065. ;        Y2         = Lower Right Ypos of Source Image
  3066. ;        DestPage   = Display Page # to copy Image to
  3067. ;        DestX1     = Xpos to Copy UL Corner of Image to
  3068. ;        DestY1     = Ypos to Copy UL Corner of Image to
  3069. ;
  3070. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  3071. ;
  3072.  
  3073. CB_STACK    STRUC
  3074.     CB_Height   DW  ?   ; Height of Image in Lines
  3075.     CB_Width    DW  ?   ; Width of Image in "bands"
  3076.                 DW  ?x4 ; DI, SI, DS, BP
  3077.                 DD  ?   ; Caller
  3078.     CB_DestY1   DW  ?   ; Destination Ypos
  3079.     CB_DestX1   DW  ?   ; Destination Xpos
  3080.     CB_DestP    DW  ?   ; Page to Copy Bitmap To
  3081.     CB_Y2       DW  ?   ; LR Ypos of Image
  3082.     CB_X2       DW  ?   ; LR Xpos of Image
  3083.     CB_Y1       DW  ?   ; UL Ypos of Image
  3084.     CB_X1       DW  ?   ; UL Xpos of Image
  3085.     CB_SourceP  DW  ?   ; Page containing Source Bitmap
  3086. CB_STACK    ENDS
  3087.  
  3088.         PUBLIC    COPY_BITMAP
  3089.  
  3090. COPY_BITMAP PROC    FAR
  3091.  
  3092.     PUSHx   BP, DS, SI, DI      ; Preserve Important Registers
  3093.     SUB     SP, 4               ; Allocate WorkSpace on Stack
  3094.     MOV     BP, SP              ; Set up Stack Frame
  3095.  
  3096.     ; Prep Registers (and keep jumps short!)
  3097.  
  3098.     MOV     ES, CURRENT_SEGMENT ; ES -> VGA Ram
  3099.     CLD                         ; Block Xfer Forwards
  3100.  
  3101.     ; Make sure Parameters are valid
  3102.  
  3103.     MOV     BX, [BP].CB_SourceP ; Get Source Page #
  3104.     CMP     BX, LAST_PAGE       ; is it > Max Page #?
  3105.     JAE     @CB_Abort           ; if so, abort
  3106.  
  3107.     MOV     CX, [BP].CB_DestP   ; Get Destination Page #
  3108.     CMP     CX, LAST_PAGE       ; is it > Max Page #?
  3109.     JAE     @CB_Abort           ; if so, abort
  3110.  
  3111.     MOV     AX, [BP].CB_X1      ; Get Source X1
  3112.     XOR     AX, [BP].CB_DestX1  ; Compare Bits 0-1
  3113.     AND     AX, PLANE_BITS      ; Check Plane Bits
  3114.     JNZ     @CB_Abort           ; They should cancel out
  3115.  
  3116.     ; Setup for Copy processing
  3117.  
  3118.     OUT_8   SC_INDEX, MAP_MASK      ; Set up for Plane Select
  3119.     OUT_16  GC_Index, LATCHES_ON    ; Data from Latches = on
  3120.  
  3121.     ; Compute Info About Images, Setup ES:SI & ES:DI
  3122.  
  3123.     MOV     AX, [BP].CB_Y2      ; Height of Bitmap in lines
  3124.     SUB     AX, [BP].CB_Y1      ; is Y2 - Y1 + 1
  3125.     INC     AX                  ; (add 1 since were not 0 based)
  3126.     MOV     [BP].CB_Height, AX  ; Save on Stack for later use
  3127.  
  3128.     MOV     AX, [BP].CB_X2      ; Get # of "Bands" of 4 Pixels
  3129.     MOV     DX, [BP].CB_X1      ; the Bitmap Occupies as X2-X1
  3130.     SHR     AX, 2               ; Get X2 Band (X2 / 4)
  3131.     SHR     DX, 2               ; Get X1 Band (X1 / 4)
  3132.     SUB     AX, DX              ; AX = # of Bands - 1
  3133.     INC     AX                  ; AX = # of Bands
  3134.     MOV     [BP].CB_Width, AX   ; Save on Stack for later use
  3135.  
  3136.     SHL     BX, 1               ; Scale Source Page to Word
  3137.     MOV     SI, PAGE_ADDR[BX]   ; SI = Offset of Source Page
  3138.     MOV     AX, [BP].CB_Y1      ; Get Source Y1 Line
  3139.     MUL     SCREEN_WIDTH        ; AX = Offset to Line Y1
  3140.     ADD     SI, AX              ; SI = Offset to Line Y1
  3141.     MOV     AX, [BP].CB_X1      ; Get Source X1
  3142.     SHR     AX, 2               ; X1 / 4 = Byte offset
  3143.     ADD     SI, AX              ; SI = Byte Offset to (X1,Y1)
  3144.  
  3145.     MOV     BX, CX              ; Dest Page Index to BX
  3146.     SHL     BX, 1               ; Scale Source Page to Word
  3147.     MOV     DI, PAGE_ADDR[BX]   ; DI = Offset of Dest Page
  3148.     MOV     AX, [BP].CB_DestY1  ; Get Dest Y1 Line
  3149.     MUL     SCREEN_WIDTH        ; AX = Offset to Line Y1
  3150.     ADD     DI, AX              ; DI = Offset to Line Y1
  3151.     MOV     AX, [BP].CB_DestX1  ; Get Dest X1
  3152.     SHR     AX, 2               ; X1 / 4 = Byte offset
  3153.     ADD     DI, AX              ; DI = Byte Offset to (D-X1,D-Y1)
  3154.  
  3155.     MOV     CX, [BP].CB_Width   ; CX = Width of Image (Bands)
  3156.     DEC     CX                  ; CX = 1?
  3157.     JE      @CB_Only_One_Band   ; 0 Means Image Width of 1 Band
  3158.  
  3159.     MOV     BX, [BP].CB_X1      ; Get Source X1
  3160.     AND     BX, PLANE_BITS      ; Aligned? (bits 0-1 = 00?)
  3161.     JZ      @CB_Check_Right     ; if so, check right alignment
  3162.     JNZ     @CB_Left_Band       ; not aligned? well..
  3163.  
  3164. @CB_Abort:
  3165.     CLR     AX                  ; Return False (Failure)
  3166.     JMP     @CB_Exit            ; and Finish Up
  3167.  
  3168.     ; Copy when Left & Right Clip Masks overlap...
  3169.  
  3170. @CB_Only_One_Band:
  3171.     MOV     BX, [BP].CB_X1          ; Get Left Clip Mask
  3172.     AND     BX, PLANE_BITS          ; Mask out Row #
  3173.     MOV     AL, Left_Clip_Mask[BX]  ; Get Left Edge Mask
  3174.     MOV     BX, [BP].CB_X2          ; Get Right Clip Mask
  3175.     AND     BX, PLANE_BITS          ; Mask out Row #
  3176.     AND     AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte
  3177.  
  3178.     OUT_8   SC_Data, AL         ; Clip For Left & Right Masks
  3179.  
  3180.     MOV     CX, [BP].CB_Height  ; CX = # of Lines to Copy
  3181.     MOV     DX, SCREEN_WIDTH    ; DX = Width of Screen
  3182.     CLR     BX                  ; BX = Offset into Image
  3183.  
  3184. @CB_One_Loop:
  3185.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3186.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3187.     ADD     BX, DX              ; Advance Offset to Next Line
  3188.     LOOPjz  CX, @CB_One_Done    ; Exit Loop if Finished
  3189.  
  3190.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3191.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3192.     ADD     BX, DX              ; Advance Offset to Next Line
  3193.     LOOPx   CX, @CB_One_Loop    ; Loop until Finished
  3194.  
  3195. @CB_One_Done:
  3196.     JMP     @CB_Finish          ; Outa Here!
  3197.  
  3198.     ; Copy Left Edge of Bitmap
  3199.  
  3200. @CB_Left_Band:
  3201.  
  3202.     OUT_8   SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask
  3203.  
  3204.     MOV     CX, [BP].CB_Height  ; CX = # of Lines to Copy
  3205.     MOV     DX, SCREEN_WIDTH    ; DX = Width of Screen
  3206.     CLR     BX                  ; BX = Offset into Image
  3207.  
  3208. @CB_Left_Loop:
  3209.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3210.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3211.     ADD     BX, DX              ; Advance Offset to Next Line
  3212.     LOOPjz  CX, @CB_Left_Done   ; Exit Loop if Finished
  3213.  
  3214.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3215.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3216.     ADD     BX, DX              ; Advance Offset to Next Line
  3217.     LOOPx   CX, @CB_Left_Loop   ; Loop until Finished
  3218.  
  3219. @CB_Left_Done:
  3220.     INC     DI                  ; Move Dest Over 1 band
  3221.     INC     SI                  ; Move Source Over 1 band
  3222.     DEC     [BP].CB_Width       ; Band Width--
  3223.  
  3224.     ; Determine if Right Edge of Bitmap needs special copy
  3225.  
  3226. @CB_Check_Right:
  3227.     MOV     BX, [BP].CB_X2      ; Get Source X2
  3228.     AND     BX, PLANE_BITS      ; Aligned? (bits 0-1 = 11?)
  3229.     CMP     BL, 03h             ; Plane = 3?
  3230.     JE      @CB_Copy_Middle     ; Copy the Middle then!
  3231.  
  3232.     ; Copy Right Edge of Bitmap
  3233.  
  3234. @CB_Right_Band:
  3235.  
  3236.     OUT_8   SC_Data, Right_Clip_Mask[BX]    ; Set Right Edge Plane Mask
  3237.  
  3238.     DEC     [BP].CB_Width       ; Band Width--
  3239.     MOV     CX, [BP].CB_Height  ; CX = # of Lines to Copy
  3240.     MOV     DX, SCREEN_WIDTH    ; DX = Width of Screen
  3241.     MOV     BX, [BP].CB_Width   ; BX = Offset to Right Edge
  3242.  
  3243. @CB_Right_Loop:
  3244.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3245.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3246.     ADD     BX, DX              ; Advance Offset to Next Line
  3247.     LOOPjz  CX, @CB_Right_Done  ; Exit Loop if Finished
  3248.  
  3249.     MOV     AL, ES:[SI+BX]      ; Load Latches
  3250.     MOV     ES:[DI+BX], AL      ; Unload Latches
  3251.     ADD     BX, DX              ; Advance Offset to Next Line
  3252.     LOOPx   CX, @CB_Right_Loop  ; Loop until Finished
  3253.  
  3254. @CB_Right_Done:
  3255.  
  3256.     ; Copy the Main Block of the Bitmap
  3257.  
  3258. @CB_Copy_Middle:
  3259.  
  3260.     MOV     CX, [BP].CB_Width   ; Get Width Remaining
  3261.     JCXZ    @CB_Finish          ; Exit if Done
  3262.  
  3263.     OUT_8   SC_Data, ALL_PLANES ; Copy all Planes
  3264.  
  3265.     MOV     DX, SCREEN_WIDTH    ; Get Width of Screen minus
  3266.     SUB     DX, CX              ; Image width (for Adjustment)
  3267.     MOV     AX, [BP].CB_Height  ; AX = # of Lines to Copy
  3268.     MOV     BX, CX              ; BX = Quick REP reload count
  3269.     MOV     CX, ES              ; Move VGA Segment
  3270.     MOV     DS, CX              ; Into DS
  3271.  
  3272.     ; Actual Copy Loop.  REP MOVSB does the work
  3273.  
  3274. @CB_Middle_Copy:
  3275.     MOV     CX, BX              ; Recharge Rep Count
  3276.     REP     MOVSB               ; Move Bands
  3277.     LOOPjz  AX, @CB_Finish      ; Exit Loop if Finished
  3278.  
  3279.     ADD     SI, DX              ; Adjust DS:SI to Next Line
  3280.     ADD     DI, DX              ; Adjust ES:DI to Next Line
  3281.  
  3282.     MOV     CX, BX              ; Recharge Rep Count
  3283.     REP     MOVSB               ; Move Bands
  3284.  
  3285.     ADD     SI, DX              ; Adjust DS:SI to Next Line
  3286.     ADD     DI, DX              ; Adjust ES:DI to Next Line
  3287.     LOOPx   AX, @CB_Middle_Copy ; Copy Lines until Done
  3288.  
  3289. @CB_Finish:
  3290.     OUT_16  GC_Index, LATCHES_OFF   ; Data from Latches = on
  3291.  
  3292. @CB_Exit:
  3293.     ADD     SP, 04              ; Deallocate stack workspace
  3294.     POPx    DI, SI, DS, BP      ; Restore Saved Registers
  3295.     RET     16                  ; Exit and Clean up Stack
  3296.  
  3297. COPY_BITMAP ENDP
  3298.  
  3299.     END                         ; End of Code Segment
  3300.